From fc15609a0f2ae2a134c34e7c9a13977994f37367 Mon Sep 17 00:00:00 2001 From: David Justo Date: Fri, 31 Jan 2025 19:40:02 -0800 Subject: [PATCH 1/7] Add the ability to opt-out of ASan container annotations on a per-allocator basis (#5241) Co-authored-by: Casey Carter Co-authored-by: Stephan T. Lavavej --- stl/inc/vector | 74 ++++++++------- stl/inc/xmemory | 4 + stl/inc/xstring | 87 +++++++++-------- .../GH_002030_asan_annotate_string/test.cpp | 69 ++++++++++++-- .../GH_002030_asan_annotate_vector/test.cpp | 95 ++++++++++++++++--- 5 files changed, 227 insertions(+), 102 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index 4f79f4986c8..27f3ad281db 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -483,48 +483,50 @@ private: _STL_INTERNAL_CHECK(_Old_last_ != nullptr); _STL_INTERNAL_CHECK(_New_last_ != nullptr); + if constexpr (!_Disable_ASan_container_annotations_for_allocator) { #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - return; - } + if (_STD is_constant_evaluated()) { + return; + } #endif // _HAS_CXX20 - if (!_Asan_vector_should_annotate) { - return; - } - - const void* const _First = _STD _Unfancy(_First_); - const void* const _End = _STD _Unfancy(_End_); - const void* const _Old_last = _STD _Unfancy(_Old_last_); - const void* const _New_last = _STD _Unfancy(_New_last_); - if constexpr ((_Container_allocation_minimum_asan_alignment) >= _Asan_granularity) { - // old state: - // [_First, _Old_last) valid - // [_Old_last, _End) poison - // new state: - // [_First, _New_last) valid - // [_New_last, asan_aligned_after(_End)) poison - _CSTD __sanitizer_annotate_contiguous_container( - _First, _STD _Get_asan_aligned_after(_End), _Old_last, _New_last); - } else { - const auto _Aligned = _STD _Get_asan_aligned_first_end(_First, _End); - if (_Aligned._First == _Aligned._End) { - // The buffer does not end at least one shadow memory section; nothing to do. + if (!_Asan_vector_should_annotate) { return; } - const void* const _Old_fixed = _Aligned._Clamp_to_end(_Old_last); - const void* const _New_fixed = _Aligned._Clamp_to_end(_New_last); - - // old state: - // [_Aligned._First, _Old_fixed) valid - // [_Old_fixed, _Aligned._End) poison - // [_Aligned._End, _End) valid - // new state: - // [_Aligned._First, _New_fixed) valid - // [_New_fixed, _Aligned._End) poison - // [_Aligned._End, _End) valid - _CSTD __sanitizer_annotate_contiguous_container(_Aligned._First, _Aligned._End, _Old_fixed, _New_fixed); + const void* const _First = _STD _Unfancy(_First_); + const void* const _End = _STD _Unfancy(_End_); + const void* const _Old_last = _STD _Unfancy(_Old_last_); + const void* const _New_last = _STD _Unfancy(_New_last_); + if constexpr ((_Container_allocation_minimum_asan_alignment) >= _Asan_granularity) { + // old state: + // [_First, _Old_last) valid + // [_Old_last, _End) poison + // new state: + // [_First, _New_last) valid + // [_New_last, asan_aligned_after(_End)) poison + _CSTD __sanitizer_annotate_contiguous_container( + _First, _STD _Get_asan_aligned_after(_End), _Old_last, _New_last); + } else { + const auto _Aligned = _STD _Get_asan_aligned_first_end(_First, _End); + if (_Aligned._First == _Aligned._End) { + // The buffer does not end at least one shadow memory section; nothing to do. + return; + } + + const void* const _Old_fixed = _Aligned._Clamp_to_end(_Old_last); + const void* const _New_fixed = _Aligned._Clamp_to_end(_New_last); + + // old state: + // [_Aligned._First, _Old_fixed) valid + // [_Old_fixed, _Aligned._End) poison + // [_Aligned._End, _End) valid + // new state: + // [_Aligned._First, _New_fixed) valid + // [_New_fixed, _Aligned._End) poison + // [_Aligned._End, _End) valid + _CSTD __sanitizer_annotate_contiguous_container(_Aligned._First, _Aligned._End, _Old_fixed, _New_fixed); + } } } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 7567d415a15..31d0bed8c98 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -805,6 +805,10 @@ struct _Simple_types { // wraps types from allocators with simple addressing for _INLINE_VAR constexpr size_t _Asan_granularity = 8; _INLINE_VAR constexpr size_t _Asan_granularity_mask = _Asan_granularity - 1; +// Controls whether ASan `container-overflow` errors are reported for this allocator. +template +constexpr bool _Disable_ASan_container_annotations_for_allocator = false; + struct _Asan_aligned_pointers { const void* _First; const void* _End; diff --git a/stl/inc/xstring b/stl/inc/xstring index 6d5954ea93f..8bf2a0a5c08 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -622,54 +622,57 @@ private: static _CONSTEXPR20 void _Apply_annotation(const value_type* const _First, const size_type _Capacity, const size_type _Old_size, const size_type _New_size) noexcept { + if constexpr (!_Disable_ASan_container_annotations_for_allocator) { #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { - return; - } + if (_STD is_constant_evaluated()) { + return; + } #endif // _HAS_CXX20 - // Don't annotate small strings; only annotate on the heap. - if (_Capacity <= _Small_string_capacity || !_Asan_string_should_annotate) { - return; - } - // Note that `_Capacity`, `_Old_size`, and `_New_size` do not include the null terminator - const void* const _End = _First + _Capacity + 1; - const void* const _Old_last = _First + _Old_size + 1; - const void* const _New_last = _First + _New_size + 1; + // Don't annotate small strings; only annotate on the heap. + if (_Capacity <= _Small_string_capacity || !_Asan_string_should_annotate) { + return; + } - constexpr bool _Large_string_always_asan_aligned = - (_Container_allocation_minimum_asan_alignment) >= _Asan_granularity; + // Note that `_Capacity`, `_Old_size`, and `_New_size` do not include the null terminator + const void* const _End = _First + _Capacity + 1; + const void* const _Old_last = _First + _Old_size + 1; + const void* const _New_last = _First + _New_size + 1; - // for the non-aligned buffer options, the buffer must always have size >= 9 bytes, - // so it will always end at least one shadow memory section. + constexpr bool _Large_string_always_asan_aligned = + (_Container_allocation_minimum_asan_alignment) >= _Asan_granularity; - _Asan_aligned_pointers _Aligned; - if constexpr (_Large_string_always_asan_aligned) { - _Aligned = {_First, _STD _Get_asan_aligned_after(_End)}; - } else { - _Aligned = _STD _Get_asan_aligned_first_end(_First, _End); - } - const void* const _Old_fixed = _Aligned._Clamp_to_end(_Old_last); - const void* const _New_fixed = _Aligned._Clamp_to_end(_New_last); - - // --- always aligned case --- - // old state: - // [_First, _Old_last) valid - // [_Old_last, asan_aligned_after(_End)) poison - // new state: - // [_First, _New_last) valid - // [_New_last, asan_aligned_after(_End)) poison - - // --- sometimes non-aligned case --- - // old state: - // [_Aligned._First, _Old_fixed) valid - // [_Old_fixed, _Aligned._End) poison - // [_Aligned._End, _End) valid - // new state: - // [_Aligned._First, _New_fixed) valid - // [_New_fixed, _Aligned._End) poison - // [_Aligned._End, _End) valid - _CSTD __sanitizer_annotate_contiguous_container(_Aligned._First, _Aligned._End, _Old_fixed, _New_fixed); + // for the non-aligned buffer options, the buffer must always have size >= 9 bytes, + // so it will always end at least one shadow memory section. + + _Asan_aligned_pointers _Aligned; + if constexpr (_Large_string_always_asan_aligned) { + _Aligned = {_First, _STD _Get_asan_aligned_after(_End)}; + } else { + _Aligned = _STD _Get_asan_aligned_first_end(_First, _End); + } + const void* const _Old_fixed = _Aligned._Clamp_to_end(_Old_last); + const void* const _New_fixed = _Aligned._Clamp_to_end(_New_last); + + // --- always aligned case --- + // old state: + // [_First, _Old_last) valid + // [_Old_last, asan_aligned_after(_End)) poison + // new state: + // [_First, _New_last) valid + // [_New_last, asan_aligned_after(_End)) poison + + // --- sometimes non-aligned case --- + // old state: + // [_Aligned._First, _Old_fixed) valid + // [_Old_fixed, _Aligned._End) poison + // [_Aligned._End, _End) valid + // new state: + // [_Aligned._First, _New_fixed) valid + // [_New_fixed, _Aligned._End) poison + // [_Aligned._End, _End) valid + _CSTD __sanitizer_annotate_contiguous_container(_Aligned._First, _Aligned._End, _Old_fixed, _New_fixed); + } } #define _ASAN_STRING_REMOVE(_Str) (_Str)._Remove_annotation() diff --git a/tests/std/tests/GH_002030_asan_annotate_string/test.cpp b/tests/std/tests/GH_002030_asan_annotate_string/test.cpp index e8bf4d30c3e..ab35b14f364 100644 --- a/tests/std/tests/GH_002030_asan_annotate_string/test.cpp +++ b/tests/std/tests/GH_002030_asan_annotate_string/test.cpp @@ -289,6 +289,29 @@ STATIC_ASSERT(_Container_allocation_minimum_asan_alignment< basic_string, implicit_allocator>> == 2); +// Simple allocator that opts out of ASan annotations (via `_Disable_ASan_container_annotations_for_allocator`) +template +struct implicit_allocator_no_asan_annotations : implicit_allocator { + implicit_allocator_no_asan_annotations() = default; + template + constexpr implicit_allocator_no_asan_annotations( + const implicit_allocator_no_asan_annotations&) noexcept {} + + T* allocate(size_t n) { + T* mem = new T[n + 1]; + return mem + 1; + } + + void deallocate(T* p, size_t) noexcept { + delete[] (p - 1); + } +}; + +template +constexpr bool + _Disable_ASan_container_annotations_for_allocator> = + true; + template void test_construction() { using CharType = typename Alloc::value_type; @@ -1855,6 +1878,28 @@ void run_tests() { #endif // ^^^ no workaround ^^^ } +// Test that writing to uninitialized memory in a string triggers an ASan container-overflow error. (See GH-5251.) +template > +void run_asan_container_overflow_death_test() { + + // We'll give the string capacity 100 (all uninitialized memory, except for the null terminator). + basic_string, Alloc> myString; + myString.reserve(100); + + // Write to the element at index 50 to trigger an ASan container-overflow check. + CharType* myData = &myString[0]; + myData[50] = CharType{'A'}; +} + +// Test that ASan `container-overflow` checks can be disabled for a custom allocator. +template +void run_asan_annotations_disablement_test() { + + // ASan annotations are disabled for the `implicit_allocator_no_asan_annotations` allocator, + // which should make the container-overflow 'death test' pass. + run_asan_container_overflow_death_test>(); +} + template class Alloc> void run_custom_allocator_matrix() { run_tests>(); @@ -1869,6 +1914,11 @@ void run_allocator_matrix() { run_custom_allocator_matrix(); run_custom_allocator_matrix(); run_custom_allocator_matrix(); + + // To test ASan annotation disablement, we use an ad-hoc allocator type to avoid disrupting other + // tests that depend on annotations being enabled. Therefore, unlike the prior tests, + // this test is not parameterized by the allocator type. + run_asan_annotations_disablement_test(); } void test_DevCom_10116361() { @@ -1919,15 +1969,6 @@ void test_gh_3955() { assert(s == t); } -void test_gh_5251() { - // GH-5251 : ASan annotations do not prevent writing to allocated - // but uninitialized basic_string memory - string myString; - myString.reserve(100); - char* myData = &myString[0]; - myData[50] = 'A'; // ASan should fire! -} - int main(int argc, char* argv[]) { std_testing::death_test_executive exec([] { run_allocator_matrix(); @@ -1944,7 +1985,15 @@ int main(int argc, char* argv[]) { test_gh_3955(); }); #ifdef __SANITIZE_ADDRESS__ - exec.add_death_tests({test_gh_5251}); + exec.add_death_tests({ + run_asan_container_overflow_death_test, +#ifdef __cpp_char8_t + run_asan_container_overflow_death_test, +#endif // __cpp_char8_t + run_asan_container_overflow_death_test, + run_asan_container_overflow_death_test, + run_asan_container_overflow_death_test, + }); #endif // ASan instrumentation enabled return exec.run(argc, argv); } diff --git a/tests/std/tests/GH_002030_asan_annotate_vector/test.cpp b/tests/std/tests/GH_002030_asan_annotate_vector/test.cpp index 93ac83e275b..300b7daf25f 100644 --- a/tests/std/tests/GH_002030_asan_annotate_vector/test.cpp +++ b/tests/std/tests/GH_002030_asan_annotate_vector/test.cpp @@ -12,6 +12,8 @@ #include #include +#include + #pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension #ifdef __clang__ @@ -53,6 +55,10 @@ struct non_trivial_can_throw { } non_trivial_can_throw& operator=(const non_trivial_can_throw&) { + ++i; + if (i == 0) { + throw i; + } return *this; } @@ -274,6 +280,29 @@ struct implicit_allocator : custom_test_allocator { STATIC_ASSERT(_Container_allocation_minimum_asan_alignment>> == 1); STATIC_ASSERT(_Container_allocation_minimum_asan_alignment>> == 2); +// Simple allocator that opts out of ASan annotations (via `_Disable_ASan_container_annotations_for_allocator`) +template +struct implicit_allocator_no_asan_annotations : implicit_allocator { + implicit_allocator_no_asan_annotations() = default; + template + constexpr implicit_allocator_no_asan_annotations( + const implicit_allocator_no_asan_annotations&) noexcept {} + + T* allocate(size_t n) { + T* mem = new T[n + 1]; + return mem + 1; + } + + void deallocate(T* p, size_t) noexcept { + delete[] (p - 1); + } +}; + +template +constexpr bool + _Disable_ASan_container_annotations_for_allocator> = + true; + template void test_push_pop() { using T = typename Alloc::value_type; @@ -1002,31 +1031,69 @@ void run_custom_allocator_matrix() { run_tests>(); } +// Test that writing to uninitialized memory in a vector triggers an ASan container-overflow error. +template > +void run_asan_container_overflow_death_test() { + // We'll give the vector capacity 100 (all uninitialized memory). + vector v; + v.reserve(100); + + // Write to the element at index 50 to trigger an ASan container-overflow check. + v.data()[50] = T{}; +} + +// Test that ASan `container-overflow` checks can be disabled for a custom allocator. +template +void run_asan_annotations_disablement_test() { + + // ASan annotations are disabled for the `implicit_allocator_no_asan_annotations` allocator, + // which should make the container-overflow 'death test' pass. + run_asan_container_overflow_death_test>(); +} + template void run_allocator_matrix() { run_tests>(); run_custom_allocator_matrix(); run_custom_allocator_matrix(); run_custom_allocator_matrix(); + + // To test ASan annotation disablement, we use an ad-hoc allocator type to avoid disrupting other + // tests that depend on annotations being enabled. Therefore, unlike the prior tests, + // this test is not parameterized by the allocator type. + run_asan_annotations_disablement_test(); } -int main() { - // Do some work even when we aren't instrumented - run_allocator_matrix(); +int main(int argc, char* argv[]) { + std_testing::death_test_executive exec([] { + // Do some work even when we aren't instrumented + run_allocator_matrix(); #ifdef __SANITIZE_ADDRESS__ - run_allocator_matrix(); - run_allocator_matrix(); - run_allocator_matrix(); - run_allocator_matrix(); + run_allocator_matrix(); + run_allocator_matrix(); + run_allocator_matrix(); + run_allocator_matrix(); #ifndef __clang__ // TRANSITION, LLVM-35365 - test_push_back_throw(); - test_emplace_back_throw(); - test_insert_range_throw(); - test_insert_throw(); - test_emplace_throw(); - test_resize_throw(); - test_insert_n_throw(); + test_push_back_throw(); + test_emplace_back_throw(); + test_insert_range_throw(); + test_insert_throw(); + test_emplace_throw(); + test_resize_throw(); + test_insert_n_throw(); #endif // ^^^ no workaround ^^^ #endif // ASan instrumentation enabled + }); + +#ifdef __SANITIZE_ADDRESS__ + exec.add_death_tests({ + run_asan_container_overflow_death_test, + run_asan_container_overflow_death_test, + run_asan_container_overflow_death_test, + run_asan_container_overflow_death_test, + }); +#endif // ASan instrumentation enabled + + return exec.run(argc, argv); } From f953153f47957144033a97611fabb9cb1c3a8b8d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 10 Feb 2025 21:06:18 -0800 Subject: [PATCH 2/7] Improve debug checks (prelude to STL Hardening) (#5270) --- docs/import_library.md | 2 +- stl/inc/__msvc_ranges_tuple_formatter.hpp | 2 +- stl/inc/__msvc_string_view.hpp | 20 +-- stl/inc/algorithm | 4 +- stl/inc/array | 28 ++-- stl/inc/atomic | 123 +++++++----------- stl/inc/bitset | 4 +- stl/inc/chrono | 7 +- stl/inc/deque | 26 ++-- stl/inc/expected | 60 ++++----- stl/inc/format | 2 +- stl/inc/forward_list | 6 +- stl/inc/generator | 6 +- stl/inc/list | 26 ++-- stl/inc/mdspan | 38 +++--- stl/inc/memory | 31 +++-- stl/inc/memory_resource | 10 +- stl/inc/numeric | 14 +- stl/inc/optional | 24 ++-- stl/inc/ranges | 34 ++--- stl/inc/regex | 5 +- stl/inc/span | 45 ++++--- stl/inc/valarray | 60 ++++----- stl/inc/vector | 46 ++++--- stl/inc/xmemory | 22 +++- stl/inc/xstring | 18 +-- stl/inc/xtree | 4 +- stl/inc/xutility | 20 +-- stl/inc/yvals.h | 52 ++------ .../P0645R10_text_formatting_death/test.cpp | 7 - .../test.cpp | 8 ++ .../P0896R4_common_iterator_death/test.cpp | 2 - .../P0896R4_counted_iterator_death/test.cpp | 2 - .../tests/P0896R4_istream_view_death/test.cpp | 2 - .../P0896R4_views_transform_death/test.cpp | 2 - .../test.cpp | 52 ++++---- .../tests/VSO_0938757_attribute_order/env.lst | 2 +- 37 files changed, 377 insertions(+), 439 deletions(-) diff --git a/docs/import_library.md b/docs/import_library.md index 124b8f3016c..b4951bbba5a 100644 --- a/docs/import_library.md +++ b/docs/import_library.md @@ -41,7 +41,7 @@ The caveats of this technique are: + This limitation is subtle (not readily apparent from the source code) and critical. If shared global state is necessary, our only option while preserving bincompat is adding a satellite DLL. * Due to having just two flavors of the import library (debug and release), - we cannot use anything that depends on `_CONTAINER_DEBUG_LEVEL` or `_ITERATOR_DEBUG_LEVEL`. + we cannot use anything that depends on `_ITERATOR_DEBUG_LEVEL`. For these reasons, especially the last one, we need to strictly control what is used by the import library. In particular, `basic_string` must not be used there. diff --git a/stl/inc/__msvc_ranges_tuple_formatter.hpp b/stl/inc/__msvc_ranges_tuple_formatter.hpp index 9b4595db7a3..5d1989e5a66 100644 --- a/stl/inc/__msvc_ranges_tuple_formatter.hpp +++ b/stl/inc/__msvc_ranges_tuple_formatter.hpp @@ -324,7 +324,7 @@ class basic_format_arg { case _Basic_format_arg_type::_Custom_type: return _STD forward<_Visitor>(_Vis)(_Custom_state); default: - _STL_VERIFY(false, "basic_format_arg is in impossible state"); + _STL_REPORT_ERROR("basic_format_arg contains an impossible type"); int _Dummy{}; return _STD forward<_Visitor>(_Vis)(_Dummy); } diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 14198cbdf6b..5e973ade480 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -1381,7 +1381,7 @@ class basic_string_view { // wrapper for any kind of contiguous character buffer : _Mydata(_Cts), _Mysize(_Count) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count == 0 || _Cts, "non-zero size null string_view"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } #if _HAS_CXX20 @@ -1476,7 +1476,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 _STL_VERIFY(_Off < _Mysize, "string_view subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // CodeQL [SM01954] This index is optionally validated above. return _Mydata[_Off]; @@ -1490,30 +1490,30 @@ 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 - _STL_VERIFY(_Mysize != 0, "cannot call front on empty string_view"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Mysize != 0, "cannot call back on empty string_view"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Mysize >= _Count, "cannot remove prefix longer than total size"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Mysize >= _Count, "cannot remove suffix longer than total size"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Mysize >= _Count, "cannot remove_suffix() larger than string_view size"); +#endif _Mysize -= _Count; } diff --git a/stl/inc/algorithm b/stl/inc/algorithm index ef3fa2e1f54..0bfef44a07b 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -7157,9 +7157,7 @@ _CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order h const auto _ULast = _STD _Get_unwrapped(_Last); #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Counterexample = _STD _Is_heap_until_unchecked(_UFirst, _ULast, _STD _Pass_fn(_Pred)); - if (_Counterexample != _ULast) { - _STL_REPORT_ERROR("invalid heap in sort_heap()"); - } + _STL_VERIFY(_Counterexample == _ULast, "invalid heap in sort_heap()"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _STD _Sort_heap_unchecked(_UFirst, _ULast, _STD _Pass_fn(_Pred)); } diff --git a/stl/inc/array b/stl/inc/array index b8eef281ba1..77bf40f14f1 100644 --- a/stl/inc/array +++ b/stl/inc/array @@ -533,7 +533,7 @@ public: _NODISCARD _CONSTEXPR17 reference operator[](_In_range_(<, _Size) size_type _Pos) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pos < _Size, "array subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Elems[_Pos]; } @@ -542,7 +542,7 @@ public: /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pos < _Size, "array subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Elems[_Pos]; } @@ -708,48 +708,48 @@ public: _NODISCARD reference operator[](size_type) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_REPORT_ERROR("array subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_REPORT_ERROR("array subscript is invalid"); +#endif return *data(); } _NODISCARD const_reference operator[](size_type) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_REPORT_ERROR("array subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_REPORT_ERROR("array subscript is invalid"); +#endif return *data(); } _NODISCARD reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_REPORT_ERROR("array::front() invalid"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_REPORT_ERROR("array::front() is invalid"); +#endif return *data(); } _NODISCARD const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_REPORT_ERROR("array::front() invalid"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_REPORT_ERROR("array::front() is invalid"); +#endif return *data(); } _NODISCARD reference back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_REPORT_ERROR("array::back() invalid"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_REPORT_ERROR("array::back() is invalid"); +#endif return *data(); } _NODISCARD const_reference back() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_REPORT_ERROR("array::back() invalid"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_REPORT_ERROR("array::back() is invalid"); +#endif return *data(); } diff --git a/stl/inc/atomic b/stl/inc/atomic index e69bb281481..000559221f9 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -134,55 +134,21 @@ extern "C" inline void _Check_memory_order(const unsigned int _Order) noexcept { #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 #define _ATOMIC_LOAD_ARM64(_Result, _Width, _Ptr, _Order_var) \ - switch (_Order_var) { \ - case _Atomic_memory_order_relaxed: \ + _Check_load_memory_order(_Order_var); \ + if (_Order_var == memory_order_relaxed) { \ _Result = __iso_volatile_load##_Width(_Ptr); \ - break; \ - case _Atomic_memory_order_consume: \ - case _Atomic_memory_order_acquire: \ - case _Atomic_memory_order_seq_cst: \ + } else { \ _Result = __LOAD_ACQUIRE_ARM64(_Width, _Ptr); \ _Compiler_barrier(); \ - break; \ - case _Atomic_memory_order_release: \ - case _Atomic_memory_order_acq_rel: \ - default: \ - _Result = __iso_volatile_load##_Width(_Ptr); \ - _INVALID_MEMORY_ORDER; \ - break; \ } #endif // _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 #define _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(_Order_var) \ - switch (_Order_var) { \ - case _Atomic_memory_order_relaxed: \ - break; \ - case _Atomic_memory_order_consume: \ - case _Atomic_memory_order_acquire: \ - case _Atomic_memory_order_seq_cst: \ + _Check_load_memory_order(_Order_var); \ + if (_Order_var != memory_order_relaxed) { \ _Compiler_or_memory_barrier(); \ - break; \ - case _Atomic_memory_order_release: \ - case _Atomic_memory_order_acq_rel: \ - default: \ - _INVALID_MEMORY_ORDER; \ - break; \ - } - -#define _ATOMIC_STORE_PREFIX(_Width, _Ptr, _Desired) \ - case _Atomic_memory_order_relaxed: \ - __iso_volatile_store##_Width((_Ptr), (_Desired)); \ - return; \ - case _Atomic_memory_order_release: \ - __STORE_RELEASE(_Width, _Ptr, _Desired); \ - return; \ - default: \ - case _Atomic_memory_order_consume: \ - case _Atomic_memory_order_acquire: \ - case _Atomic_memory_order_acq_rel: \ - _INVALID_MEMORY_ORDER; \ - _FALLTHROUGH; + } #define _ATOMIC_STORE_SEQ_CST_ARM(_Width, _Ptr, _Desired) \ _Memory_barrier(); \ @@ -731,11 +697,15 @@ struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics void store(const _TVal _Value, const memory_order _Order) noexcept { // store with given memory order const auto _Mem = _STD _Atomic_address_as(_Storage); const char _As_bytes = _STD _Atomic_reinterpret_as(_Value); - switch (static_cast(_Order)) { - _ATOMIC_STORE_PREFIX(8, _Mem, _As_bytes) - case _Atomic_memory_order_seq_cst: + + _Check_store_memory_order(_Order); + + if (_Order == memory_order_relaxed) { + __iso_volatile_store8(_Mem, _As_bytes); + } else if (_Order == memory_order_release) { + __STORE_RELEASE(8, _Mem, _As_bytes); + } else { store(_Value); - return; } } @@ -744,10 +714,10 @@ struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics const auto _Mem = _STD _Atomic_address_as(_Storage); char _As_bytes; #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 - _ATOMIC_LOAD_ARM64(_As_bytes, 8, _Mem, static_cast(_Order)) + _ATOMIC_LOAD_ARM64(_As_bytes, 8, _Mem, _Order) #else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 vvv _As_bytes = __iso_volatile_load8(_Mem); - _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(static_cast(_Order)) + _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(_Order) #endif // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 ^^^ return reinterpret_cast<_TVal&>(_As_bytes); } @@ -834,11 +804,15 @@ struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics void store(const _TVal _Value, const memory_order _Order) noexcept { // store with given memory order const auto _Mem = _STD _Atomic_address_as(_Storage); const short _As_bytes = _STD _Atomic_reinterpret_as(_Value); - switch (static_cast(_Order)) { - _ATOMIC_STORE_PREFIX(16, _Mem, _As_bytes) - case _Atomic_memory_order_seq_cst: + + _Check_store_memory_order(_Order); + + if (_Order == memory_order_relaxed) { + __iso_volatile_store16(_Mem, _As_bytes); + } else if (_Order == memory_order_release) { + __STORE_RELEASE(16, _Mem, _As_bytes); + } else { store(_Value); - return; } } @@ -847,10 +821,10 @@ struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics const auto _Mem = _STD _Atomic_address_as(_Storage); short _As_bytes; #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 - _ATOMIC_LOAD_ARM64(_As_bytes, 16, _Mem, static_cast(_Order)) + _ATOMIC_LOAD_ARM64(_As_bytes, 16, _Mem, _Order) #else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 vvv _As_bytes = __iso_volatile_load16(_Mem); - _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(static_cast(_Order)) + _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(_Order) #endif // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 ^^^ return reinterpret_cast<_TVal&>(_As_bytes); } @@ -936,11 +910,15 @@ struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics void store(const _TVal _Value, const memory_order _Order) noexcept { // store with given memory order const auto _Mem = _STD _Atomic_address_as(_Storage); const int _As_bytes = _STD _Atomic_reinterpret_as(_Value); - switch (static_cast(_Order)) { - _ATOMIC_STORE_PREFIX(32, _Mem, _As_bytes) - case _Atomic_memory_order_seq_cst: + + _Check_store_memory_order(_Order); + + if (_Order == memory_order_relaxed) { + __iso_volatile_store32(_Mem, _As_bytes); + } else if (_Order == memory_order_release) { + __STORE_RELEASE(32, _Mem, _As_bytes); + } else { store(_Value); - return; } } @@ -949,10 +927,10 @@ struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics const auto _Mem = _STD _Atomic_address_as(_Storage); int _As_bytes; #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 - _ATOMIC_LOAD_ARM64(_As_bytes, 32, _Mem, static_cast(_Order)) + _ATOMIC_LOAD_ARM64(_As_bytes, 32, _Mem, _Order) #else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 vvv _As_bytes = __iso_volatile_load32(_Mem); - _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(static_cast(_Order)) + _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(_Order) #endif // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 0 ^^^ return reinterpret_cast<_TVal&>(_As_bytes); } @@ -1038,11 +1016,15 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics void store(const _TVal _Value, const memory_order _Order) noexcept { // store with given memory order const auto _Mem = _STD _Atomic_address_as(_Storage); const long long _As_bytes = _STD _Atomic_reinterpret_as(_Value); - switch (static_cast(_Order)) { - _ATOMIC_STORE_PREFIX(64, _Mem, _As_bytes) - case _Atomic_memory_order_seq_cst: + + _Check_store_memory_order(_Order); + + if (_Order == memory_order_relaxed) { + __iso_volatile_store64(_Mem, _As_bytes); + } else if (_Order == memory_order_release) { + __STORE_RELEASE(64, _Mem, _As_bytes); + } else { store(_Value); - return; } } @@ -1051,7 +1033,7 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics const auto _Mem = _STD _Atomic_address_as(_Storage); long long _As_bytes; #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 - _ATOMIC_LOAD_ARM64(_As_bytes, 64, _Mem, static_cast(_Order)) + _ATOMIC_LOAD_ARM64(_As_bytes, 64, _Mem, _Order) #else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR != 1 vvv #ifdef _M_ARM @@ -1060,7 +1042,7 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics _As_bytes = __iso_volatile_load64(_Mem); #endif - _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(static_cast(_Order)) + _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(_Order) #endif // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR != 1 ^^^ return reinterpret_cast<_TVal&>(_As_bytes); } @@ -1180,9 +1162,9 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics case memory_order_acquire: (void) _INTRIN_ACQUIRE(_InterlockedCompareExchange128)(_Storage_ptr, 0, 0, &_Result._Low); break; - default: case memory_order_release: case memory_order_acq_rel: + default: _INVALID_MEMORY_ORDER; _FALLTHROUGH; case memory_order_seq_cst: @@ -2328,7 +2310,8 @@ public: explicit atomic_ref(_Ty& _Value) noexcept /* strengthened */ : _Base(_Value) { if constexpr (is_always_lock_free) { - _Check_alignment(_Value); + _STL_ASSERT((reinterpret_cast(_STD addressof(_Value)) & (required_alignment - 1)) == 0, + "atomic_ref underlying object is not aligned as required_alignment"); } else { this->_Init_spinlock_for_ref(); } @@ -2436,13 +2419,6 @@ public: { const_cast(this)->_Base::notify_all(); } - -private: - static void _Check_alignment([[maybe_unused]] const _Ty& _Value) { - _ATOMIC_REF_CHECK_ALIGNMENT( - (reinterpret_cast(_STD addressof(_Value)) & (required_alignment - 1)) == 0, - "atomic_ref underlying object is not aligned as required_alignment"); - } }; #endif // _HAS_CXX20 @@ -3042,7 +3018,6 @@ _STD_END #undef _ATOMIC_CHOOSE_INTRINSIC #undef _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED -#undef _ATOMIC_STORE_PREFIX #undef _ATOMIC_STORE_SEQ_CST_ARM #undef _ATOMIC_STORE_SEQ_CST_X86_X64 #undef _ATOMIC_STORE_32_SEQ_CST_X86_X64 diff --git a/stl/inc/bitset b/stl/inc/bitset index b6e493d957c..7374ea0676b 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -120,7 +120,7 @@ private: #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Pos; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv - _STL_VERIFY(_Pos < _Bits, "bitset index outside range"); + _STL_VERIFY(_Pos < _Bits, "bitset subscript out of range"); #endif // ^^^ _ITERATOR_DEBUG_LEVEL != 0 ^^^ } @@ -132,7 +132,7 @@ private: static constexpr unsigned long long _Mask = (1ULL << (_Need_mask ? _Bits : 0)) - 1ULL; public: - _NODISCARD constexpr bool operator[](size_t _Pos) const noexcept /* strengthened */ { + _NODISCARD constexpr bool operator[](const size_t _Pos) const noexcept /* strengthened */ { _Validate(_Pos); return _Subscript(_Pos); } diff --git a/stl/inc/chrono b/stl/inc/chrono index c017d6b5068..b71235f710d 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -1608,8 +1608,11 @@ namespace chrono { // Returns the number of fractional digits of _Num / _Den in the range [0, 18]. // If it can't be represented, 6 is returned. // Example: _Fractional_width(1, 8) would return 3 for 0.125. - auto _Den = _Duration::period::den; - _STL_ASSERT(_Duration::period::num > 0 && _Den > 0, "Numerator and denominator can't be less than 1."); + + _STL_INTERNAL_STATIC_ASSERT(_Duration::period::num > 0); // N5001 [time.duration.general]/3 + _STL_INTERNAL_STATIC_ASSERT(_Duration::period::den > 0); // N5001 [ratio.ratio]/1, /2.2 + + auto _Den = _Duration::period::den; unsigned int _Power_of_2_in_den = 0u; unsigned int _Power_of_5_in_den = 0u; for (; _Den % 2 == 0; _Den /= 2, ++_Power_of_2_in_den) { diff --git a/stl/inc/deque b/stl/inc/deque index 9bba528c614..cab1a2a804e 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1065,7 +1065,7 @@ public: _NODISCARD const_reference operator[](size_type _Pos) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Subscript(_Pos); } @@ -1073,7 +1073,7 @@ public: _NODISCARD reference operator[](size_type _Pos) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Subscript(_Pos); } @@ -1097,7 +1097,7 @@ public: _NODISCARD reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(!empty(), "front() called on empty deque"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Subscript(0); } @@ -1105,7 +1105,7 @@ public: _NODISCARD const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(!empty(), "front() called on empty deque"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Subscript(0); } @@ -1113,7 +1113,7 @@ public: _NODISCARD reference back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(!empty(), "back() called on empty deque"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Subscript(_Mysize() - 1); } @@ -1121,7 +1121,7 @@ public: _NODISCARD const_reference back() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(!empty(), "back() called on empty deque"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Subscript(_Mysize() - 1); } @@ -1475,7 +1475,7 @@ public: void pop_front() noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL == 2 if (empty()) { - _STL_REPORT_ERROR("deque empty before pop"); + _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())); @@ -1498,7 +1498,7 @@ public: void pop_back() noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL == 2 if (empty()) { - _STL_REPORT_ERROR("deque empty before pop"); + _STL_REPORT_ERROR("pop_back() called on empty deque"); } else { // something to erase, do it size_type _Newoff = _Myoff() + _Mysize() - 1; _Orphan_off(_Newoff); @@ -1528,14 +1528,14 @@ public: #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_First <= _Last && begin() <= _First && _Last <= end(), "deque erase iterator outside range"); _STD _Adl_verify_range(_First, _Last); +#endif auto _Off = static_cast(_First - begin()); auto _Count = static_cast(_Last - _First); - bool _Moved = _Off > 0 && _Off + _Count < _Mysize(); -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 / _ITERATOR_DEBUG_LEVEL < 2 vvv - auto _Off = static_cast(_First - begin()); - auto _Count = static_cast(_Last - _First); -#endif // ^^^ _ITERATOR_DEBUG_LEVEL < 2 ^^^ + +#if _ITERATOR_DEBUG_LEVEL == 2 + const bool _Moved = _Off > 0 && _Off + _Count < _Mysize(); +#endif if (_Count == 0) { return _First; diff --git a/stl/inc/expected b/stl/inc/expected index f27e3fc7007..45eb51a5fb6 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -621,39 +621,39 @@ public: // [expected.object.obs] _NODISCARD constexpr const _Ty* operator->() const noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Has_value, "expected stores an error, not a value"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Has_value, "expected stores an error, not a value"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Has_value, "expected stores an error, not a value"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Has_value, "expected stores an error, not a value"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Has_value, "expected stores an error, not a value"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Has_value, "expected stores an error, not a value"); -#endif // _CONTAINER_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); } @@ -707,26 +707,26 @@ public: _NODISCARD constexpr const _Err& error() const& noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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); } @@ -1469,8 +1469,8 @@ public: constexpr void operator*() const noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Has_value, "expected stores an error, not a value"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Has_value, "operator*() called on a std::expected that contains an error, not a value"); +#endif } constexpr void value() const& { @@ -1490,26 +1490,26 @@ public: _NODISCARD constexpr const _Err& error() const& noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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 - _STL_VERIFY(!_Has_value, "expected stores a value, not an error"); -#endif // _CONTAINER_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/format b/stl/inc/format index 53b960dbdd6..74bda572cef 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -2698,7 +2698,7 @@ struct _Arg_formatter { _Basic_format_specs<_CharT>* _Specs = nullptr; _OutputIt operator()(basic_format_arg<_Context>::handle) { - _STL_VERIFY(false, "The custom handler should be structurally unreachable for _Arg_formatter"); + _STL_REPORT_ERROR("The custom handler should be structurally unreachable for _Arg_formatter"); _STL_INTERNAL_CHECK(_Ctx); return _Ctx->out(); } diff --git a/stl/inc/forward_list b/stl/inc/forward_list index 0d556e5639a..3e801e48e23 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -131,7 +131,7 @@ public: _NODISCARD reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot dereference value-initialized forward_list iterator"); + _STL_VERIFY(_Mycont, "cannot dereference value-initialized forward_list iterator"); _STL_VERIFY(this->_Ptr != _Mycont->_Before_head(), "cannot dereference forward_list before_begin"); #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -902,7 +902,7 @@ public: _NODISCARD reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Myhead != nullptr, "front() called on empty forward_list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myhead->_Myval; } @@ -910,7 +910,7 @@ public: _NODISCARD const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Myhead != nullptr, "front() called on empty forward_list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myhead->_Myval; } diff --git a/stl/inc/generator b/stl/inc/generator index 524b9a22687..09c16afc339 100644 --- a/stl/inc/generator +++ b/stl/inc/generator @@ -479,14 +479,14 @@ namespace _Gen_detail { noexcept(noexcept(static_cast<_Ref>(*_Coro.promise()._Get_top().promise()._Ptr))) /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(!_Coro.done(), "Can't dereference generator end iterator"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return static_cast<_Ref>(*_Coro.promise()._Get_top().promise()._Ptr); } _Iterator& operator++() { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(!_Coro.done(), "Can't increment generator end iterator"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif _Coro.promise()._Get_top().resume(); return *this; } @@ -567,7 +567,7 @@ public: // Pre: _Coro is suspended at its initial suspend point #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Coro, "Can't call begin on moved-from generator"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif _Coro.resume(); return typename _Gen_detail::_Iter_provider<_Value, _Ref>::_Iterator{_Gen_detail::_Secret_tag{}, coroutine_handle<_Gen_detail::_Promise_base>::from_address(_Coro.address())}; diff --git a/stl/inc/list b/stl/inc/list index 58d87142ffe..fc5093dca87 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -143,7 +143,7 @@ public: _NODISCARD reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot dereference value-initialized list iterator"); + _STL_VERIFY(_Mycont, "cannot dereference value-initialized list iterator"); _STL_VERIFY(this->_Ptr != _Mycont->_Myhead, "cannot dereference end list iterator"); #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -157,7 +157,7 @@ public: _List_const_iterator& operator++() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot increment value-initialized list iterator"); + _STL_VERIFY(_Mycont, "cannot increment value-initialized list iterator"); _STL_VERIFY(this->_Ptr != _Mycont->_Myhead, "cannot increment end list iterator"); #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -175,7 +175,7 @@ public: const auto _New_ptr = this->_Ptr->_Prev; #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot decrement value-initialized list iterator"); + _STL_VERIFY(_Mycont, "cannot decrement value-initialized list iterator"); _STL_VERIFY(_New_ptr != _Mycont->_Myhead, "cannot decrement begin list iterator"); #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -1210,7 +1210,7 @@ public: _NODISCARD reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myhead->_Next->_Myval; } @@ -1218,7 +1218,7 @@ public: _NODISCARD const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myhead->_Next->_Myval; } @@ -1226,7 +1226,7 @@ public: _NODISCARD reference back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myhead->_Prev->_Myval; } @@ -1234,7 +1234,7 @@ public: _NODISCARD const_reference back() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myhead->_Prev->_Myval; } @@ -1254,8 +1254,8 @@ public: void pop_front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_front called on empty list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_front() called on empty list"); +#endif _Unchecked_erase(_Mypair._Myval2._Myhead->_Next); } @@ -1275,8 +1275,8 @@ public: void pop_back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_back called on empty list"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_back() called on empty list"); +#endif _Unchecked_erase(_Mypair._Myval2._Myhead->_Prev); } @@ -1543,9 +1543,7 @@ public: const auto _UFirst = _First._Ptr; #if _ITERATOR_DEBUG_LEVEL == 2 - if (_UFirst == _Right._Mypair._Myval2._Myhead) { - _STL_REPORT_ERROR("list splice iterator outside range"); - } + _STL_VERIFY(_UFirst != _Right._Mypair._Myval2._Myhead, "list splice iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 const auto _ULast = _UFirst->_Next; diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 99b6b7333bf..714c6120c71 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -185,14 +185,14 @@ public: _NODISCARD static constexpr size_t static_extent(_In_range_(<, _Rank) const rank_type _Idx) noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Static_extents[_Idx]; } _NODISCARD constexpr index_type extent(_In_range_(<, _Rank) const rank_type _Idx) const noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/3)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif if constexpr (rank_dynamic() == 0) { return static_cast(_Static_extents[_Idx]); } else if constexpr (rank_dynamic() == rank()) { @@ -465,7 +465,7 @@ struct _Maybe_fully_static_extents<_Extents> { constexpr explicit _Maybe_fully_static_extents([[maybe_unused]] const _OtherExtents& _Exts_) { #if _CONTAINER_DEBUG_LEVEL > 0 (void) _Extents{_Exts_}; // NB: temporary created for preconditions check -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } static constexpr _Extents _Exts{}; @@ -513,7 +513,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]/4)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } template @@ -525,7 +525,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]/7)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } template @@ -597,7 +597,7 @@ public: #if _CONTAINER_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 // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Fwd_prod_of_extents::_Calculate(this->_Exts, _Idx); } @@ -616,7 +616,7 @@ private: _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)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif index_type _Stride = 1; index_type _Result = 0; @@ -667,7 +667,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]/4)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } template @@ -679,7 +679,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]/7)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } template @@ -750,7 +750,7 @@ public: #if _CONTAINER_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 // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Rev_prod_of_extents::_Calculate(this->_Exts, _Idx); } @@ -769,7 +769,7 @@ private: _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)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif index_type _Result = 0; ((_Result = static_cast(_Indices + this->_Exts.extent(_Seq) * _Result)), ...); @@ -900,7 +900,7 @@ public: #if _CONTAINER_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 // _CONTAINER_DEBUG_LEVEL > 0 +#endif this->_Array[_Idx] = static_cast(_Stride); } } @@ -977,12 +977,13 @@ public: _NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept { if constexpr (extents_type::rank() == 0) { - _STL_VERIFY(false, "The argument to stride must be nonnegative and less than extents_type::rank()."); + _STL_REPORT_ERROR("The argument to stride must be nonnegative and less than extents_type::rank()."); + return 1; } else { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Idx < extents_type::_Rank, "The argument to stride must be nonnegative and less than extents_type::rank()."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return this->_Array[_Idx]; } } @@ -1031,7 +1032,7 @@ private: _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)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return static_cast(((_Indices * this->_Array[_Seq]) + ... + 0)); } @@ -1202,7 +1203,7 @@ public: _NODISCARD static constexpr size_t static_extent(_In_range_(<, extents_type::_Rank) const rank_type _Idx) noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Idx < extents_type::_Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return extents_type::_Static_extents[_Idx]; } @@ -1435,8 +1436,9 @@ private: _STL_INTERNAL_STATIC_ASSERT(conjunction_v...>); #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Map.extents()._Contains_multidimensional_index(make_index_sequence{}, _Indices...), - "I must be a multidimensional index in extents() (N4950 [mdspan.mdspan.members]/3)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + "mdspan subscript out of range; extents_type::index-cast(std::move(indices)) must be " + "a multidimensional index in extents() (N5001 [mdspan.mdspan.members]/3)."); +#endif return this->_Acc.access(_Ptr, static_cast(this->_Map(_Indices...))); } diff --git a/stl/inc/memory b/stl/inc/memory index 49d0e0af838..3770d48706d 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -92,24 +92,31 @@ namespace ranges { _STL_INTERNAL_STATIC_ASSERT(_No_throw_sentinel_for<_OSe, _Out>); _STL_INTERNAL_STATIC_ASSERT(constructible_from, iter_reference_t<_It>>); - constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; - constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; - if constexpr (_Iter_copy_cat<_It, _Out>::_Bitcopy_constructible - && _Sized_or_unreachable_sentinel_for<_Se, _It> - && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { + constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; + constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; + constexpr bool _Can_memcpy = _Iter_copy_cat<_It, _Out>::_Bitcopy_constructible + && _Sized_or_unreachable_sentinel_for<_Se, _It> + && _Sized_or_unreachable_sentinel_for<_OSe, _Out>; + if constexpr (_Can_memcpy && (_Is_sized1 || _Is_sized2)) { if constexpr (_Is_sized1 && _Is_sized2) { return _RANGES _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else if constexpr (_Is_sized1) { return _RANGES _Copy_memcpy_distance( _IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); - } else if constexpr (_Is_sized2) { + } else { + _STL_INTERNAL_STATIC_ASSERT(_Is_sized2); return _RANGES _Copy_memcpy_distance( _IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - } else { - _STL_ASSERT(false, "Tried to uninitialized_copy two ranges with unreachable sentinels"); } } else { + if constexpr (_Can_memcpy) { + // We were eligible for the memcpy optimization above, except for both sentinels being unreachable. + // The following classic code is doomed, because no exceptions will end the infinite loop. + // Following our usual pattern, let's emit a debug assertion, then run the loop anyways. + _STL_ASSERT(false, "Tried to std::uninitialized_copy() two ranges with unreachable sentinels"); + } + _Uninitialized_backout _Backout{_STD move(_OFirst)}; for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { @@ -1042,18 +1049,10 @@ public: } _NODISCARD _Ty& operator*() const noexcept { -#if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY(_Myptr, "auto_ptr not dereferenceable"); -#endif // _ITERATOR_DEBUG_LEVEL == 2 - return *get(); } _NODISCARD _Ty* operator->() const noexcept { -#if _ITERATOR_DEBUG_LEVEL == 2 - _STL_VERIFY(_Myptr, "auto_ptr not dereferenceable"); -#endif // _ITERATOR_DEBUG_LEVEL == 2 - return get(); } diff --git a/stl/inc/memory_resource b/stl/inc/memory_resource index dc66ebaa365..141524b3b40 100644 --- a/stl/inc/memory_resource +++ b/stl/inc/memory_resource @@ -361,12 +361,10 @@ namespace pmr { void _Deallocate_oversized(void* _Ptr, size_t _Bytes, size_t _Align) noexcept { // deallocate a block directly from the upstream resource - if (!_Prepare_oversized(_Bytes, _Align)) { - // no room for header + alignment padding; this memory WAS NOT allocated by this pool resource -#ifdef _DEBUG - _STL_REPORT_ERROR("Cannot deallocate memory not allocated by this memory pool."); -#endif // defined(_DEBUG) - } + [[maybe_unused]] const bool _Has_room_for_padding = _Prepare_oversized(_Bytes, _Align); + + // If there's no room for header + alignment padding, this memory WAS NOT allocated by this pool resource + _STL_ASSERT(_Has_room_for_padding, "Cannot deallocate memory not allocated by this memory pool."); _Oversized_header* _Hdr = reinterpret_cast<_Oversized_header*>(static_cast(_Ptr) + _Bytes) - 1; diff --git a/stl/inc/numeric b/stl/inc/numeric index 5b564506268..338abe4ca3c 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -671,10 +671,9 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) n #endif // ^^^ !defined(_DEBUG) ^^^ { constexpr auto _Min_common = _STD _Min_limit<_Common>(); - if (_Mx == _Min_common || _Nx == _Min_common) { - _STL_REPORT_ERROR("Preconditions: |m| and |n| are representable as a value of common_type_t. " - "(N4981 [numeric.ops.gcd]/2, N4981 [numeric.ops.lcm]/2)"); - } + _STL_VERIFY(_Mx != _Min_common && _Nx != _Min_common, + "Preconditions: |m| and |n| are representable as a value of common_type_t. " + "(N4981 [numeric.ops.gcd]/2, N4981 [numeric.ops.lcm]/2)"); } } @@ -731,11 +730,10 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> lcm(const _Mt _Mx, const _Nt _Nx) n _Common_unsigned _Result = 0; _Common_unsigned _Tmp = static_cast<_Common_unsigned>(_Mx_magnitude / _STD gcd(_Mx_magnitude, _Nx_magnitude)); + const bool _Overflow = _Mul_overflow(_Tmp, _Nx_magnitude, _Result) || !_In_range<_Common>(_Result); - if (_Mul_overflow(_Tmp, _Nx_magnitude, _Result) || !_In_range<_Common>(_Result)) { - _STL_REPORT_ERROR("Preconditions: The least common multiple of |m| and |n| is representable as a value of " - "type common_type_t. (N4981 [numeric.ops.lcm]/2)"); - } + _STL_VERIFY(!_Overflow, "Preconditions: The least common multiple of |m| and |n| is representable as a value of " + "type common_type_t. (N4981 [numeric.ops.lcm]/2)"); return static_cast<_Common>(_Result); } diff --git a/stl/inc/optional b/stl/inc/optional index 28e41c46abf..7a527fff616 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -182,29 +182,29 @@ struct _Optional_construct_base : _Optional_destruct_base<_Ty> { _NODISCARD constexpr _Ty& operator*() & noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); -#endif // _CONTAINER_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 - _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); -#endif // _CONTAINER_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 - _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); -#endif // _CONTAINER_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 - _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(this->_Has_value, "operator*() called on empty optional"); +#endif return _STD move(this->_Value); } }; @@ -377,14 +377,14 @@ public: _NODISCARD constexpr const _Ty* operator->() const noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); -#endif // _CONTAINER_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 - _STL_VERIFY(this->_Has_value, "Cannot access value of empty optional"); -#endif // _CONTAINER_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 53da3d6daa2..3af972f8847 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -1112,7 +1112,7 @@ namespace ranges { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Current < (numeric_limits<_Index_type>::max)(), "cannot increment repeat_view iterator past end (integer overflow)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif ++_Current; return *this; } @@ -1761,7 +1761,7 @@ namespace ranges { _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "filter_view has no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *_Pred; } @@ -1769,7 +1769,7 @@ namespace ranges { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY( _Pred, "N4950 [range.filter.view]/3 forbids calling begin on a filter_view that holds no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif if constexpr (forward_range<_Vw>) { if (this->_Has_cache()) { return _Iterator{*this, this->_Get_cache(_Range)}; @@ -1917,7 +1917,7 @@ namespace ranges { : _Range(_STD move(_Range_)), _Count{_Count_} { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count_ >= 0, "Number of elements to take must be non-negative (N4971 [range.take.view]/1)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ @@ -2225,7 +2225,7 @@ namespace ranges { _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "take_while_view has no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *_Pred; } @@ -2247,7 +2247,7 @@ namespace ranges { { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "cannot call end on a take_while_view with no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Sentinel{_RANGES end(_Range), _STD addressof(*_Pred)}; } @@ -2257,7 +2257,7 @@ namespace ranges { { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "cannot call end on a take_while_view with no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Sentinel{_RANGES end(_Range), _STD addressof(*_Pred)}; } }; @@ -2337,7 +2337,7 @@ namespace ranges { : _Range(_STD move(_Range_)), _Count{_Count_} { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count_ >= 0, "Number of elements to drop must be non-negative (N4971 [range.drop.view]/1)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ @@ -2559,7 +2559,7 @@ namespace ranges { _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "drop_while_view has no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *_Pred; } @@ -2567,7 +2567,7 @@ namespace ranges { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY( _Pred, "N4950 [range.drop.while.view]/3 forbids calling begin on a drop_while_view with no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif if constexpr (forward_range<_Vw>) { if (this->_Has_cache()) { return this->_Get_cache(_Range); @@ -4239,7 +4239,7 @@ namespace ranges { const iter_difference_t> _Count) _CONST_CALL_OPERATOR noexcept(_Choice<_It>._No_throw) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count >= 0, "The size passed to views::counted must be non-negative"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif constexpr _St _Strat = _Choice<_It>._Strategy; if constexpr (_Strat == _St::_Span) { @@ -5671,7 +5671,7 @@ namespace ranges { : _Range(_STD move(_Range_)), _Count{_Count_} { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count > 0, "chunk size must be greater than 0"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ @@ -5944,7 +5944,7 @@ namespace ranges { : _Range(_STD move(_Range_)), _Count{_Count_} { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count > 0, "chunk size must be greater than 0"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ @@ -6321,7 +6321,7 @@ namespace ranges { : _Range(_STD move(_Range_)), _Count{_Count_} { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count > 0, "The window size must be positive (N4950 [range.slide.view]/1)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened @@ -6597,14 +6597,14 @@ namespace ranges { _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "chunk_by_view has no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *_Pred; } _NODISCARD constexpr _Iterator begin() { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "cannot call begin on a chunk_by_view with no predicate"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const auto _First = _RANGES begin(_Range); if (this->_Has_cache()) { @@ -6929,7 +6929,7 @@ namespace ranges { : _Range(_STD move(_Range_)), _Stride(_Stride_) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Stride > 0, "stride must be greater than 0"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif } _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened diff --git a/stl/inc/regex b/stl/inc/regex index 5491b129ed0..d4988266506 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -3683,10 +3683,9 @@ bool _Matcher<_BidIt, _Elem, _RxTraits, _It>::_Match_pat(_Node_base* _Nx) { // c case _N_none: default: #if _ITERATOR_DEBUG_LEVEL != 0 - _STL_VERIFY(false, "internal data of regex node corrupted"); -#else // ^^^ _ITERATOR_DEBUG_LEVEL != 0 / _ITERATOR_DEBUG_LEVEL == 0 vvv + _STL_REPORT_ERROR("internal data of regex node corrupted"); +#endif return false; -#endif // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ } if (_Failed) { diff --git a/stl/inc/span b/stl/inc/span index bae1370bff2..4f043ea279d 100644 --- a/stl/inc/span +++ b/stl/inc/span @@ -99,7 +99,10 @@ struct _Span_iterator { } constexpr _Span_iterator& operator+=(const difference_type _Off) noexcept { +#if _ITERATOR_DEBUG_LEVEL >= 1 _Verify_offset(_Off); +#endif // _ITERATOR_DEBUG_LEVEL >= 1 + _Myptr += _Off; return *this; } @@ -116,8 +119,11 @@ struct _Span_iterator { } constexpr _Span_iterator& operator-=(const difference_type _Off) noexcept { +#if _ITERATOR_DEBUG_LEVEL >= 1 _STL_VERIFY(_Off != _Min_possible_v, "integer overflow"); _Verify_offset(-_Off); +#endif // _ITERATOR_DEBUG_LEVEL >= 1 + _Myptr -= _Off; return *this; } @@ -351,32 +357,31 @@ public: template _NODISCARD constexpr auto first() const noexcept /* strengthened */ { if constexpr (_Extent != dynamic_extent) { - static_assert(_Count <= _Extent, "Count out of range in span::first()"); + static_assert(_Count <= _Extent, "Count out of range in span::first()"); } #if _CONTAINER_DEBUG_LEVEL > 0 else { - _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::first()"); + _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::first()"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return span{_Mydata, _Count}; } - _NODISCARD constexpr auto first(const size_type _Count) const noexcept - /* strengthened */ { + _NODISCARD constexpr auto first(const size_type _Count) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::first(count)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return span{_Mydata, _Count}; } template _NODISCARD constexpr auto last() const noexcept /* strengthened */ { if constexpr (_Extent != dynamic_extent) { - static_assert(_Count <= _Extent, "Count out of range in span::last()"); + static_assert(_Count <= _Extent, "Count out of range in span::last()"); } #if _CONTAINER_DEBUG_LEVEL > 0 else { - _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::last()"); + _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::last()"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return span{_Mydata + (_Mysize - _Count), _Count}; @@ -385,23 +390,23 @@ public: _NODISCARD constexpr auto last(const size_type _Count) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::last(count)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return span{_Mydata + (_Mysize - _Count), _Count}; } template _NODISCARD constexpr auto subspan() const noexcept /* strengthened */ { if constexpr (_Extent != dynamic_extent) { - static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()"); - static_assert( - _Count == dynamic_extent || _Count <= _Extent - _Offset, "Count out of range in span::subspan()"); + static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()"); + static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset, + "Count out of range in span::subspan()"); } #if _CONTAINER_DEBUG_LEVEL > 0 else { - _STL_VERIFY(_Offset <= _Mysize, "Offset out of range in span::subspan()"); + _STL_VERIFY(_Offset <= _Mysize, "Offset out of range in span::subspan()"); if constexpr (_Count != dynamic_extent) { - _STL_VERIFY(_Count <= _Mysize - _Offset, "Count out of range in span::subspan()"); + _STL_VERIFY(_Count <= _Mysize - _Offset, "Count out of range in span::subspan()"); } } #endif // _CONTAINER_DEBUG_LEVEL > 0 @@ -432,7 +437,7 @@ public: #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize <= dynamic_extent / sizeof(element_type), "size of span in bytes exceeds std::numeric_limits::max()"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mysize * sizeof(element_type); } #pragma warning(pop) @@ -444,8 +449,8 @@ public: // [span.elem] Element access _NODISCARD constexpr reference operator[](const size_type _Off) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Off < _Mysize, "span index out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_Off < _Mysize, "span subscript out of range"); +#endif return _Mydata[_Off]; } @@ -453,15 +458,15 @@ public: #pragma warning(disable : 4127) // conditional expression is constant _NODISCARD constexpr reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Mysize > 0, "front of empty span"); -#endif // _CONTAINER_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 - _STL_VERIFY(_Mysize > 0, "back of empty span"); -#endif // _CONTAINER_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 3b370470e1d..5773a639e20 100644 --- a/stl/inc/valarray +++ b/stl/inc/valarray @@ -292,7 +292,7 @@ public: valarray& operator*=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] *= _Right[_Idx]; @@ -303,7 +303,7 @@ public: valarray& operator/=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] /= _Right[_Idx]; @@ -314,7 +314,7 @@ public: valarray& operator%=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] %= _Right[_Idx]; @@ -325,7 +325,7 @@ public: valarray& operator+=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] += _Right[_Idx]; @@ -336,7 +336,7 @@ public: valarray& operator-=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] -= _Right[_Idx]; @@ -347,7 +347,7 @@ public: valarray& operator^=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] ^= _Right[_Idx]; @@ -358,7 +358,7 @@ public: valarray& operator|=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] |= _Right[_Idx]; @@ -369,7 +369,7 @@ public: valarray& operator&=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] &= _Right[_Idx]; @@ -380,7 +380,7 @@ public: valarray& operator<<=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] <<= _Right[_Idx]; @@ -391,7 +391,7 @@ public: valarray& operator>>=(const valarray& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { _Myptr[_Idx] >>= _Right[_Idx]; @@ -406,7 +406,7 @@ public: _NODISCARD const _Ty& operator[](size_t _Off) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off < _Mysize, "valarray subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Myptr[_Off]; } @@ -414,7 +414,7 @@ public: _NODISCARD _Ty& operator[](size_t _Off) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off < _Mysize, "valarray subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Myptr[_Off]; } @@ -868,7 +868,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator*(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -881,7 +881,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator/(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -894,7 +894,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator%(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -907,7 +907,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator+(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -920,7 +920,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator-(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -933,7 +933,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator^(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -946,7 +946,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator&(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -959,7 +959,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator|(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -972,7 +972,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator<<(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -985,7 +985,7 @@ _EXPORT_STD template _NODISCARD valarray<_Ty> operator>>(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray<_Ty> _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -998,7 +998,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator&&(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1011,7 +1011,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator||(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1044,7 +1044,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator==(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1077,7 +1077,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator!=(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1110,7 +1110,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator<(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1143,7 +1143,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator>(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1176,7 +1176,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator<=(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1209,7 +1209,7 @@ _EXPORT_STD template _NODISCARD _Boolarray operator>=(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const size_t _Size = _Left.size(); valarray _Ans(_Size); for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { diff --git a/stl/inc/vector b/stl/inc/vector index 27f3ad281db..ae8330bf2d2 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -1737,8 +1737,8 @@ public: pointer& _Mylast = _My_data._Mylast; #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_My_data._Myfirst != _Mylast, "vector empty before pop"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(_My_data._Myfirst != _Mylast, "pop_back() called on empty vector"); +#endif _Orphan_range(_Mylast - 1, _Mylast); _Alty_traits::destroy(_Getal(), _Unfancy(_Mylast - 1)); @@ -1916,7 +1916,7 @@ public: #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY( _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _My_data._Myfirst[_Pos]; } @@ -1926,7 +1926,7 @@ public: #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY( _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _My_data._Myfirst[_Pos]; } @@ -1953,7 +1953,7 @@ public: auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *_My_data._Myfirst; } @@ -1962,7 +1962,7 @@ public: auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *_My_data._Myfirst; } @@ -1971,7 +1971,7 @@ public: auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _My_data._Mylast[-1]; } @@ -1980,7 +1980,7 @@ public: auto& _My_data = _Mypair._Myval2; #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _My_data._Mylast[-1]; } @@ -3211,7 +3211,7 @@ public: _NODISCARD _CONSTEXPR20 const_reference operator[](size_type _Off) const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off < this->_Mysize, "vector subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif const_iterator _It = begin(); _It._Advance(_Off); @@ -3221,7 +3221,7 @@ public: _NODISCARD _CONSTEXPR20 reference operator[](size_type _Off) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off < this->_Mysize, "vector subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif iterator _It = begin(); _It._Advance(_Off); @@ -3231,7 +3231,7 @@ public: _NODISCARD _CONSTEXPR20 reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "front() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *begin(); } @@ -3239,7 +3239,7 @@ public: _NODISCARD _CONSTEXPR20 const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "front() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *begin(); } @@ -3247,7 +3247,7 @@ public: _NODISCARD _CONSTEXPR20 reference back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "back() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *(end() - 1); } @@ -3255,7 +3255,7 @@ public: _NODISCARD _CONSTEXPR20 const_reference back() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Mysize != 0, "back() called on empty vector"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return *(end() - 1); } @@ -3422,11 +3422,13 @@ public: #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(end() > _Where, "vector erase iterator outside range"); +#endif + _STD copy(_Next_iter(_Where), end(), _Where); + +#if _ITERATOR_DEBUG_LEVEL == 2 _Orphan_range(static_cast(_Off), this->_Mysize); -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 / _ITERATOR_DEBUG_LEVEL < 2 vvv - _STD copy(_Next_iter(_Where), end(), _Where); -#endif // ^^^ _ITERATOR_DEBUG_LEVEL < 2 ^^^ +#endif _Trim(this->_Mysize - 1); return begin() + _Off; @@ -3441,14 +3443,16 @@ public: if (_First != _Last) { // worth doing, copy down over hole #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_Last >= _First && end() >= _Last, "vector erase iterator outside range"); +#endif + iterator _Next = _STD copy(_Last, end(), _First); const auto _Newsize = static_cast(_Next - begin()); + +#if _ITERATOR_DEBUG_LEVEL == 2 _Orphan_range(_Newsize, this->_Mysize); +#endif + _Trim(_Newsize); -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 / _ITERATOR_DEBUG_LEVEL < 2 vvv - iterator _Next = _STD copy(_Last, end(), _First); - _Trim(static_cast(_Next - begin())); -#endif // ^^^ _ITERATOR_DEBUG_LEVEL < 2 ^^^ } return begin() + _Off; } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 31d0bed8c98..acac82131e1 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1786,23 +1786,31 @@ namespace ranges { requires (constructible_from, iter_rvalue_reference_t<_It>>) uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked( _It _IFirst, _Se _ILast, _Out _OFirst, _OSe _OLast) { - constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; - constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; - if constexpr (_Iter_move_cat<_It, _Out>::_Bitcopy_constructible && _Sized_or_unreachable_sentinel_for<_Se, _It> - && _Sized_or_unreachable_sentinel_for<_OSe, _Out>) { + constexpr bool _Is_sized1 = sized_sentinel_for<_Se, _It>; + constexpr bool _Is_sized2 = sized_sentinel_for<_OSe, _Out>; + constexpr bool _Can_memcpy = _Iter_move_cat<_It, _Out>::_Bitcopy_constructible + && _Sized_or_unreachable_sentinel_for<_Se, _It> + && _Sized_or_unreachable_sentinel_for<_OSe, _Out>; + if constexpr (_Can_memcpy && (_Is_sized1 || _Is_sized2)) { if constexpr (_Is_sized1 && _Is_sized2) { return _RANGES _Copy_memcpy_common(_IFirst, _RANGES next(_IFirst, _STD move(_ILast)), _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); } else if constexpr (_Is_sized1) { return _RANGES _Copy_memcpy_distance( _IFirst, _OFirst, _IFirst, _RANGES next(_IFirst, _STD move(_ILast))); - } else if constexpr (_Is_sized2) { + } else { + _STL_INTERNAL_STATIC_ASSERT(_Is_sized2); return _RANGES _Copy_memcpy_distance( _IFirst, _OFirst, _OFirst, _RANGES next(_OFirst, _STD move(_OLast))); - } else { - _STL_ASSERT(false, "Tried to uninitialized_move two ranges with unreachable sentinels"); } } else { + if constexpr (_Can_memcpy) { + // We were eligible for the memcpy optimization above, except for both sentinels being unreachable. + // The following classic code is doomed, because no exceptions will end the infinite loop. + // Following our usual pattern, let's emit a debug assertion, then run the loop anyways. + _STL_ASSERT(false, "Tried to std::uninitialized_move() two ranges with unreachable sentinels"); + } + _Uninitialized_backout _Backout{_STD move(_OFirst)}; for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) { diff --git a/stl/inc/xstring b/stl/inc/xstring index 8bf2a0a5c08..e18772035bf 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -106,9 +106,9 @@ public: return; } - _STL_ASSERT(_Ptr, "cannot seek value-initialized string iterator"); + _STL_VERIFY(_Ptr, "cannot seek value-initialized string iterator"); const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot seek string iterator because the iterator was " + _STL_VERIFY(_Mycont, "cannot seek string iterator because the iterator was " "invalidated (e.g. reallocation occurred, or the string was destroyed)"); const auto _Contptr = _Mycont->_Myptr(); const auto _Rawptr = _Unfancy(_Ptr); @@ -2248,7 +2248,7 @@ public: _NODISCARD _CONSTEXPR20 reference operator[](const size_type _Off) noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off <= _Mypair._Myval2._Mysize, "string subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myptr()[_Off]; } @@ -2256,7 +2256,7 @@ public: /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Off <= _Mypair._Myval2._Mysize, "string subscript out of range"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myptr()[_Off]; } @@ -2292,7 +2292,7 @@ public: _CONSTEXPR20 void pop_back() noexcept /* strengthened */ { const size_type _Old_size = _Mypair._Myval2._Mysize; #if _ITERATOR_DEBUG_LEVEL >= 1 - _STL_VERIFY(_Old_size != 0, "invalid to pop_back empty string"); + _STL_VERIFY(_Old_size != 0, "pop_back() called on empty string"); #endif // _ITERATOR_DEBUG_LEVEL >= 1 _Eos(_Old_size - 1); } @@ -2300,7 +2300,7 @@ public: _NODISCARD _CONSTEXPR20 reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty string"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myptr()[0]; } @@ -2308,7 +2308,7 @@ public: _NODISCARD _CONSTEXPR20 const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty string"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myptr()[0]; } @@ -2316,7 +2316,7 @@ public: _NODISCARD _CONSTEXPR20 reference back() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty string"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myptr()[_Mypair._Myval2._Mysize - 1]; } @@ -2324,7 +2324,7 @@ public: _NODISCARD _CONSTEXPR20 const_reference back() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty string"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif return _Mypair._Myval2._Myptr()[_Mypair._Myval2._Mysize - 1]; } diff --git a/stl/inc/xtree b/stl/inc/xtree index 0ec8c6fce12..9738b831130 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -178,7 +178,7 @@ public: _NODISCARD reference operator*() const noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Mycont = static_cast(this->_Getcont()); - _STL_ASSERT(_Mycont, "cannot dereference value-initialized map/set iterator"); + _STL_VERIFY(_Mycont, "cannot dereference value-initialized map/set iterator"); _STL_VERIFY(this->_Ptr != _Mycont->_Myhead, "cannot dereference end map/set iterator"); #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -207,7 +207,7 @@ public: _Tree_const_iterator& operator--() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 - _STL_ASSERT(this->_Getcont(), "cannot decrement value-initialized map/set iterator"); + _STL_VERIFY(this->_Getcont(), "cannot decrement value-initialized map/set iterator"); _Nodeptr _Ptrsav = this->_Ptr; _Mybase::operator--(); _STL_VERIFY(_Ptrsav != this->_Ptr, "cannot decrement begin map/set iterator"); diff --git a/stl/inc/xutility b/stl/inc/xutility index d31e7079341..0c5c942a29d 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3824,8 +3824,8 @@ namespace ranges { { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(!_RANGES empty(_Self), "front called on empty view_interface"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "front() called on empty ranges::view_interface"); +#endif return *_RANGES begin(_Self); } @@ -3834,8 +3834,8 @@ namespace ranges { { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(!_RANGES empty(_Self), "front called on empty view_interface"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "front() called on empty ranges::view_interface"); +#endif return *_RANGES begin(_Self); } @@ -3844,8 +3844,8 @@ namespace ranges { { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(!_RANGES empty(_Self), "back called on empty view_interface"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "back() called on empty ranges::view_interface"); +#endif auto _Last = _RANGES end(_Self); return *--_Last; } @@ -3855,8 +3855,8 @@ namespace ranges { { auto& _Self = _Cast(); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(!_RANGES empty(_Self), "back called on empty view_interface"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 + _STL_VERIFY(!_RANGES empty(_Self), "back() called on empty ranges::view_interface"); +#endif auto _Last = _RANGES end(_Self); return *--_Last; } @@ -3868,7 +3868,7 @@ namespace ranges { 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)), - "index out of range for view_interface"); + "ranges::view_interface subscript out of range"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _RANGES begin(_Self)[_Idx]; @@ -3881,7 +3881,7 @@ namespace ranges { 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)), - "index out of range for view_interface"); + "ranges::view_interface subscript out of range"); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return _RANGES begin(_Self)[_Idx]; diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index 33ac7c51203..5922af50231 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -181,35 +181,15 @@ _STL_DISABLE_CLANG_WARNINGS #endif // ^^^ !defined(_DEBUG) ^^^ #endif // !defined(_STL_CRT_SECURE_INVALID_PARAMETER) -#define _STL_REPORT_ERROR(mesg) \ - do { \ - _RPTF0(_CRT_ASSERT, mesg); \ - _STL_CRT_SECURE_INVALID_PARAMETER(mesg); \ - } while (false) - -#ifdef __clang__ -#define _STL_VERIFY(cond, mesg) \ - _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wassume\"") do { \ - if (cond) { /* contextually convertible to bool paranoia */ \ - } else { \ - _STL_REPORT_ERROR(mesg); \ - } \ - \ - _Analysis_assume_(cond); \ - } \ - while (false) \ - _Pragma("clang diagnostic pop") -#else // ^^^ Clang / MSVC vvv -#define _STL_VERIFY(cond, mesg) \ - do { \ - if (cond) { /* contextually convertible to bool paranoia */ \ - } else { \ - _STL_REPORT_ERROR(mesg); \ - } \ - \ - _Analysis_assume_(cond); \ - } while (false) -#endif // ^^^ MSVC ^^^ +#define _STL_REPORT_ERROR(mesg) \ + _RPTF0(_CRT_ASSERT, mesg); \ + _STL_CRT_SECURE_INVALID_PARAMETER(mesg) + +#define _STL_VERIFY(cond, mesg) \ + if (!(cond)) { \ + _STL_REPORT_ERROR(mesg); \ + } \ + _Analysis_assume_(cond) #ifdef _DEBUG #define _STL_ASSERT(cond, mesg) _STL_VERIFY(cond, mesg) @@ -223,20 +203,6 @@ _STL_DISABLE_CLANG_WARNINGS #define _STL_INTERNAL_CHECK(...) _Analysis_assume_(__VA_ARGS__) #endif // ^^^ !defined(_ENABLE_STL_INTERNAL_CHECK) ^^^ -#ifndef _ENABLE_ATOMIC_REF_ALIGNMENT_CHECK -#ifdef _DEBUG -#define _ENABLE_ATOMIC_REF_ALIGNMENT_CHECK 1 -#else // ^^^ defined(_DEBUG) / !defined(_DEBUG) vvv -#define _ENABLE_ATOMIC_REF_ALIGNMENT_CHECK 0 -#endif // ^^^ !defined(_DEBUG) ^^^ -#endif // !defined(_ENABLE_ATOMIC_REF_ALIGNMENT_CHECK) - -#if _ENABLE_ATOMIC_REF_ALIGNMENT_CHECK -#define _ATOMIC_REF_CHECK_ALIGNMENT(cond, mesg) _STL_VERIFY(cond, mesg) -#else -#define _ATOMIC_REF_CHECK_ALIGNMENT(cond, mesg) _Analysis_assume_(cond) -#endif - #include #ifdef _STATIC_CPPLIB diff --git a/tests/std/tests/P0645R10_text_formatting_death/test.cpp b/tests/std/tests/P0645R10_text_formatting_death/test.cpp index e09eba9dc28..a19bab56c5d 100644 --- a/tests/std/tests/P0645R10_text_formatting_death/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_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 @@ -17,17 +15,12 @@ void test_case_advance_no_range() { context.advance_to(other_format_string.begin()); } -void test_case_negative_dynamic_width() { - (void) format("{:{}}", 42, -2); -} - int main(int argc, char* argv[]) { std_testing::death_test_executive exec; #if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_case_advance_no_range, - test_case_negative_dynamic_width, }); #endif // _ITERATOR_DEBUG_LEVEL != 0 diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index 4273f2f9909..ff1a01f2636 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1386,6 +1386,10 @@ void libfmt_formatter_test_runtime_width() { assert(format(STR("{0:{1}}"), reinterpret_cast(0xcafe), 10) == STR(" 0xcafe")); assert(format(STR("{0:{1}}"), 'x', 11) == STR("x ")); assert(format(STR("{0:{1}}"), STR("str"), 12) == STR("str ")); + + // Test positive and negative dynamic width: + assert(format(STR("{:{}}"), 42, 5) == STR(" 42")); + throw_helper(STR("{:{}}"), 42, -5); } template @@ -1425,6 +1429,10 @@ void libfmt_formatter_test_runtime_precision() { throw_helper(STR("{:.{}f}"), 3.14f, true); throw_helper(STR("{:.{}f}"), 3.14f, '0'); assert(format(STR("{:.{}f}"), 3.14f, static_cast(2)) == STR("3.14")); + + // Test positive and negative dynamic precision: + assert(format(STR("{:.{}}"), 3.14159265358979, 5) == STR("3.1416")); + throw_helper(STR("{:.{}}"), 3.14159265358979, -5); } template diff --git a/tests/std/tests/P0896R4_common_iterator_death/test.cpp b/tests/std/tests/P0896R4_common_iterator_death/test.cpp index 20facf56200..18bd1004ab6 100644 --- a/tests/std/tests/P0896R4_common_iterator_death/test.cpp +++ b/tests/std/tests/P0896R4_common_iterator_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 diff --git a/tests/std/tests/P0896R4_counted_iterator_death/test.cpp b/tests/std/tests/P0896R4_counted_iterator_death/test.cpp index dce76063cb5..92e06bb9e54 100644 --- a/tests/std/tests/P0896R4_counted_iterator_death/test.cpp +++ b/tests/std/tests/P0896R4_counted_iterator_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 diff --git a/tests/std/tests/P0896R4_istream_view_death/test.cpp b/tests/std/tests/P0896R4_istream_view_death/test.cpp index fbad6ceae6b..85aca7e4f48 100644 --- a/tests/std/tests/P0896R4_istream_view_death/test.cpp +++ b/tests/std/tests/P0896R4_istream_view_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 diff --git a/tests/std/tests/P0896R4_views_transform_death/test.cpp b/tests/std/tests/P0896R4_views_transform_death/test.cpp index 6ab18e88984..7eb908f1723 100644 --- a/tests/std/tests/P0896R4_views_transform_death/test.cpp +++ b/tests/std/tests/P0896R4_views_transform_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 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 0f11348804a..29b47050c76 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 @@ -13,6 +13,12 @@ using namespace std; +#pragma warning(disable : 4984) // 'if constexpr' is a C++17 language extension + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wc++17-extensions" // constexpr if is a C++17 extension +#endif + template struct TestCases { using ContainerType = typename Traits::ContainerType; @@ -26,15 +32,11 @@ struct TestCases { (void) *it; } - static void test_case_operator_arrow_value_initialized_iterator2(true_type) { - IteratorType it; - (void) it.operator->(); - } - - static void test_case_operator_arrow_value_initialized_iterator2(false_type) {} - static void test_case_operator_arrow_value_initialized_iterator() { - return test_case_operator_arrow_value_initialized_iterator2(bool_constant{}); + if constexpr (Traits::has_arrow) { + IteratorType it; + (void) it.operator->(); + } } static void test_case_operator_preincrement_value_initialized_iterator() { @@ -73,16 +75,12 @@ struct TestCases { (void) *it; } - static void test_case_operator_arrow_end_iterator2(true_type) { - ContainerType a{false, true, false, true}; - auto it = a.end(); - (void) it.operator->(); - } - - static void test_case_operator_arrow_end_iterator2(false_type) {} - static void test_case_operator_arrow_end_iterator() { - return test_case_operator_arrow_end_iterator2(bool_constant{}); + if constexpr (Traits::has_arrow) { + ContainerType a{false, true, false, true}; + auto it = a.end(); + (void) it.operator->(); + } } static void test_case_operator_preincrement_off_end() { @@ -186,8 +184,7 @@ struct TestCases { static void add_cases(std_testing::death_test_executive& exec) { #if _ITERATOR_DEBUG_LEVEL != 0 - static constexpr std_testing::death_function_t a[] = { - // TRANSITION, VSO-847348 + exec.add_death_tests({ test_case_operator_dereference_value_initialized_iterator, test_case_operator_preincrement_value_initialized_iterator, test_case_operator_predecrement_value_initialized_iterator, @@ -206,27 +203,22 @@ struct TestCases { test_case_operator_equal_incompatible_value_initialized, test_case_operator_less_incompatible_different_views, test_case_operator_less_incompatible_value_initialized, - }; - exec.add_death_tests(a); + }); - if (Traits::has_arrow) { - static constexpr std_testing::death_function_t b[] = { - // TRANSITION, VSO-847348 + if constexpr (Traits::has_arrow) { + exec.add_death_tests({ test_case_operator_arrow_value_initialized_iterator, test_case_operator_arrow_end_iterator, - }; - exec.add_death_tests(b); + }); } #endif // _ITERATOR_DEBUG_LEVEL != 0 - static constexpr std_testing::death_function_t c[] = { - // TRANSITION, VSO-847348 + 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, - }; - exec.add_death_tests(c); + }); } }; diff --git a/tests/std/tests/VSO_0938757_attribute_order/env.lst b/tests/std/tests/VSO_0938757_attribute_order/env.lst index e11f90f1dfb..b73794175a9 100644 --- a/tests/std/tests/VSO_0938757_attribute_order/env.lst +++ b/tests/std/tests/VSO_0938757_attribute_order/env.lst @@ -3,4 +3,4 @@ RUNALL_INCLUDE ..\prefix.lst RUNALL_CROSSLIST -PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MTd /std:c++latest /permissive- /D_PREFAST_ -Wno-ignored-attributes" +PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MTd /std:c++latest /permissive- /D_PREFAST_ -Wno-ignored-attributes -Wno-assume" From 3f7ca671925c0be8aacd1630de1ba0c301df97d4 Mon Sep 17 00:00:00 2001 From: Alex Prabhat Bara Date: Tue, 11 Feb 2025 10:42:10 +0530 Subject: [PATCH 3/7] : Alternate form general floating-point width handling (#5261) Co-authored-by: alexprabhatbara --- stl/inc/format | 2 ++ tests/std/tests/P0645R10_text_formatting_formatting/test.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/stl/inc/format b/stl/inc/format index 74bda572cef..034610661f1 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -2145,6 +2145,8 @@ _NODISCARD _OutputIt _Fmt_write( case 'g': if (_Precision == -1) { _Precision = 6; + } else if (_Precision == 0) { + _Precision = 1; } _Format = chars_format::general; break; diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index ff1a01f2636..f6fc8bdbde3 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -835,6 +835,7 @@ void test_float_specs() { assert(format(STR("{:3}"), Float{0}) == STR(" 0")); assert(format(STR("{:#9G}"), Float{12.2}) == STR(" 12.2000")); assert(format(STR("{:#12g}"), Float{1'000'000}) == STR(" 1.00000e+06")); + assert(format(STR("[{:#6.0g}]"), 1.234e-37) == STR("[1.e-37]")); // Precision Float value = 1234.52734375; From d43d49a3fdfa9d4fdbafd82dc517250b93269c94 Mon Sep 17 00:00:00 2001 From: Paulina Kalicka <71526180+paulinek13@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:20:18 +0100 Subject: [PATCH 4/7] Update `_MSVC_STL_UPDATE` to February 2025 (#5264) --- 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 0a2a75fd9da..2bd67b707b9 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -905,7 +905,7 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 143 -#define _MSVC_STL_UPDATE 202501L +#define _MSVC_STL_UPDATE 202502L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #if defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) From 977a92e41a93e7911d72879f80203e26dbf26b2c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 18 Feb 2025 15:03:40 -0800 Subject: [PATCH 5/7] Update libcxx skips for a new compiler warning (#5283) --- tests/libcxx/expected_results.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 52c4877f626..3fd6165a3c6 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -1381,3 +1381,9 @@ std/containers/sequences/vector/vector.modifiers/assert.push_back.invalidation.p # This test is marked as `REQUIRES: has-unix-headers, libcpp-has-abi-bounded-iterators-in-std-array`. # Listing these on separate lines would allow magic_comments.txt to recognize it. std/containers/sequences/array/assert.iterators.pass.cpp:9 SKIPPED + +# These tests emit C5321, which warns when the resolution to core issue 1656 affects a u8 string literal. +# The conformant behavior is opt-in because it can silently change behavior. +# : warning C5321: nonstandard extension used: encoding '\x80' as a multi-byte utf-8 character. Use \u instead for cross platform compatibility or '/Zc:u8EscapeEncoding' to disable the extension. +std/utilities/format/format.functions/escaped_output.unicode.pass.cpp:9 SKIPPED +std/utilities/format/format.functions/fill.unicode.pass.cpp:9 SKIPPED From a4e32acc25b3599410d82ec04414e9a0263384c7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 19 Feb 2025 23:51:33 -0800 Subject: [PATCH 6/7] Toolset update: VS 2022 17.14 Preview 1 (#5284) --- .gitignore | 2 +- README.md | 4 +- azure-devops/config.yml | 2 +- azure-devops/create-1es-hosted-pool.ps1 | 41 +++++------ azure-devops/provision-image.ps1 | 12 +++- benchmarks/google-benchmark | 2 +- stl/inc/__msvc_bit_utils.hpp | 14 ++-- stl/inc/__msvc_ranges_to.hpp | 2 +- stl/inc/__msvc_ranges_tuple_formatter.hpp | 2 +- stl/inc/experimental/filesystem | 2 +- stl/inc/functional | 4 +- stl/inc/memory_resource | 6 +- stl/inc/mutex | 2 +- stl/inc/ranges | 21 +++--- stl/inc/xstring | 24 +++---- stl/inc/xutility | 25 +++---- stl/inc/yvals_core.h | 22 ++++-- stl/src/vector_algorithms.cpp | 8 ++- tests/libcxx/expected_results.txt | 69 ++++++------------- .../test.compile.pass.cpp | 4 -- tools/scripts/print_failures.py | 5 +- 21 files changed, 136 insertions(+), 137 deletions(-) diff --git a/.gitignore b/.gitignore index 961cfd602f3..f9438ec8ca5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ __pycache__/ /out/ /tools/out/ /CMakeLists.txt.user -/*.log +*.log diff --git a/README.md b/README.md index 02ade81ea2d..2600f98cee3 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.13 Preview 4 or later. +1. Install Visual Studio 2022 17.14 Preview 1 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. * Select "MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)" in the VS Installer if you would like to build the ARM64/ARM64EC target. @@ -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.13 Preview 4 or later. +1. Install Visual Studio 2022 17.14 Preview 1 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. * Select "MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)" in the VS Installer if you would like to build the ARM64/ARM64EC target. diff --git a/azure-devops/config.yml b/azure-devops/config.yml index fc8be111087..732fe64fe9f 100644 --- a/azure-devops/config.yml +++ b/azure-devops/config.yml @@ -5,7 +5,7 @@ variables: - name: poolName - value: 'StlBuild-2025-01-28T1106-Pool' + value: 'StlBuild-2025-02-15T0137-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 205e17ad75f..aa99a024346 100644 --- a/azure-devops/create-1es-hosted-pool.ps1 +++ b/azure-devops/create-1es-hosted-pool.ps1 @@ -18,8 +18,9 @@ $VMSize = 'Standard_F32as_v6' $ProtoVMName = 'PROTOTYPE' $ImagePublisher = 'MicrosoftWindowsServer' $ImageOffer = 'WindowsServer' -$ImageSku = '2025-datacenter-g2' +$ImageSku = '2025-datacenter-azure-edition' +$LogFile = '1es-hosted-pool.log' $ProgressActivity = 'Preparing STL CI pool' $TotalProgress = 26 $CurrentProgress = 1 @@ -78,13 +79,13 @@ $Env:SuppressAzurePowerShellBreakingChangeWarnings = 'true' Update-AzConfig ` -DisplayBreakingChangeWarning $false ` - -Scope 'Process' | Out-Null + -Scope 'Process' >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Setting the subscription context' Set-AzContext ` - -SubscriptionName 'CPP_STL_GitHub' | Out-Null + -SubscriptionName 'CPP_STL_GitHub' >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Creating resource group' @@ -93,7 +94,7 @@ $ResourceGroupName = 'StlBuild-' + $CurrentDate.ToString('yyyy-MM-ddTHHmm') New-AzResourceGroup ` -Name $ResourceGroupName ` - -Location $Location | Out-Null + -Location $Location >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Creating credentials' @@ -169,7 +170,7 @@ $VM = Set-AzVMBootDiagnostic ` New-AzVm ` -ResourceGroupName $ResourceGroupName ` -Location $Location ` - -VM $VM | Out-Null + -VM $VM >> $LogFile $VM = Get-AzVM ` -ResourceGroupName $ResourceGroupName ` @@ -192,7 +193,7 @@ if ($ProvisionImageResult.value.Message -cnotmatch 'PROVISION_IMAGE_SUCCEEDED') Stop-AzVM ` -Id $VM.ID ` - -Force | Out-Null + -Force >> $LogFile Write-Error "VM stopped. Remember to delete unusable resource group: $ResourceGroupName" } @@ -201,7 +202,7 @@ if ($ProvisionImageResult.value.Message -cnotmatch 'PROVISION_IMAGE_SUCCEEDED') Display-ProgressBar -Status 'Restarting VM' Restart-AzVM ` - -Id $VM.ID | Out-Null + -Id $VM.ID >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Sleeping after restart' @@ -216,7 +217,7 @@ Display-ProgressBar -Status 'Running sysprep in VM' Invoke-AzVMRunCommand ` -ResourceId $VM.ID ` -CommandId 'RunPowerShellScript' ` - -ScriptString 'C:\Windows\system32\sysprep\sysprep.exe /oobe /generalize /mode:vm /shutdown' | Out-Null + -ScriptString 'C:\Windows\system32\sysprep\sysprep.exe /oobe /generalize /mode:vm /shutdown' >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Waiting for VM to shut down' @@ -230,14 +231,14 @@ Display-ProgressBar -Status 'Stopping VM' Stop-AzVM ` -Id $VM.ID ` - -Force | Out-Null + -Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Generalizing VM' Set-AzVM ` -Id $VM.ID ` - -Generalized | Out-Null + -Generalized >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Creating gallery' @@ -256,7 +257,7 @@ $ServicePrincipalObjectId = (Get-AzADServicePrincipal -DisplayName '1ES Resource New-AzRoleAssignment ` -ObjectId $ServicePrincipalObjectId ` -RoleDefinitionName 'Reader' ` - -Scope $Gallery.Id | Out-Null + -Scope $Gallery.Id >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Creating image definition' @@ -276,7 +277,7 @@ New-AzGalleryImageDefinition ` -Offer $ImageOffer ` -Sku $ImageSku ` -Feature $ImageDefinitionFeatures ` - -HyperVGeneration 'V2' | Out-Null + -HyperVGeneration 'V2' >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Creating image version' @@ -294,7 +295,7 @@ $ImageVersion = New-AzGalleryImageVersion ` Display-ProgressBar -Status 'Registering CloudTest resource provider' Register-AzResourceProvider ` - -ProviderNamespace 'Microsoft.CloudTest' | Out-Null + -ProviderNamespace 'Microsoft.CloudTest' >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Creating 1ES image' @@ -306,7 +307,7 @@ New-AzResource ` -ResourceType 'Microsoft.CloudTest/Images' ` -ResourceName $ImageName ` -Properties @{ 'imageType' = 'SharedImageGallery'; 'resourceId' = $ImageVersion.Id; } ` - -Force | Out-Null + -Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Creating 1ES Hosted Pool' @@ -328,14 +329,14 @@ New-AzResource ` -ResourceType 'Microsoft.CloudTest/hostedpools' ` -ResourceName $PoolName ` -Properties $PoolProperties ` - -Force | Out-Null + -Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Deleting unused VM' Remove-AzVM ` -Id $VM.ID ` - -Force | Out-Null + -Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Deleting unused disk' @@ -343,7 +344,7 @@ Display-ProgressBar -Status 'Deleting unused disk' Remove-AzDisk ` -ResourceGroupName $ResourceGroupName ` -DiskName $PrototypeOSDiskName ` - -Force | Out-Null + -Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Deleting unused network interface' @@ -351,7 +352,7 @@ Display-ProgressBar -Status 'Deleting unused network interface' Remove-AzNetworkInterface ` -ResourceGroupName $ResourceGroupName ` -Name $NicName ` --Force | Out-Null +-Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Deleting unused virtual network' @@ -359,7 +360,7 @@ Display-ProgressBar -Status 'Deleting unused virtual network' Remove-AzVirtualNetwork ` -ResourceGroupName $ResourceGroupName ` -Name $VirtualNetworkName ` --Force | Out-Null +-Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Deleting unused network security group' @@ -367,7 +368,7 @@ Display-ProgressBar -Status 'Deleting unused network security group' Remove-AzNetworkSecurityGroup ` -ResourceGroupName $ResourceGroupName ` -Name $NetworkSecurityGroupName ` --Force | Out-Null +-Force >> $LogFile #################################################################################################### Write-Progress -Activity $ProgressActivity -Completed diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index 6a29f6e03f1..ea42153a8d5 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -43,11 +43,13 @@ foreach ($workload in $VisualStudioWorkloads) { $PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.0/PowerShell-7.5.0-win-x64.msi' $PowerShellArgs = @('/quiet', '/norestart') -$PythonUrl = 'https://www.python.org/ftp/python/3.13.1/python-3.13.1-amd64.exe' +$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') +$CudaArgs = @('-s', '-n', 'nvcc_12.4', 'cudart_12.4') +$CudaPath = 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\bin' <# .SYNOPSIS @@ -112,6 +114,12 @@ 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/benchmarks/google-benchmark b/benchmarks/google-benchmark index a6ad7fbbdc2..c58e6d07105 160000 --- a/benchmarks/google-benchmark +++ b/benchmarks/google-benchmark @@ -1 +1 @@ -Subproject commit a6ad7fbbdc2e14fab82bb8a6d27760d700198cbf +Subproject commit c58e6d0710581e3a08d65c349664128a8d9a2461 diff --git a/stl/inc/__msvc_bit_utils.hpp b/stl/inc/__msvc_bit_utils.hpp index 48567e8d523..a89221adec0 100644 --- a/stl/inc/__msvc_bit_utils.hpp +++ b/stl/inc/__msvc_bit_utils.hpp @@ -337,19 +337,19 @@ constexpr decltype(auto) _Select_countr_zero_impl(_Fn _Callback) { #if _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 if (!_STD is_constant_evaluated()) { #ifdef __AVX2__ - return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_tzcnt(_Val); }); + return _Callback([](_Ty _Val) _STATIC_LAMBDA { return _Countr_zero_tzcnt(_Val); }); #else // ^^^ AVX2 / not AVX2 vvv const bool _Definitely_have_tzcnt = __isa_available >= _Stl_isa_available_avx2; if (_Definitely_have_tzcnt) { - return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_tzcnt(_Val); }); + return _Callback([](_Ty _Val) _STATIC_LAMBDA { return _Countr_zero_tzcnt(_Val); }); } else { - return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_bsf(_Val); }); + return _Callback([](_Ty _Val) _STATIC_LAMBDA { return _Countr_zero_bsf(_Val); }); } #endif // ^^^ not AVX2 ^^^ } #endif // ^^^ _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 ^^^ // C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation. - return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Countr_zero_fallback(_Val); }); + return _Callback([](_Ty _Val) _STATIC_LAMBDA { return _Countr_zero_fallback(_Val); }); } template , int> = 0> @@ -376,13 +376,13 @@ _CONSTEXPR20 decltype(auto) _Select_popcount_impl(_Fn _Callback) { #if !_POPCNT_INTRINSICS_ALWAYS_AVAILABLE const bool _Definitely_have_popcnt = __isa_available >= _Stl_isa_available_sse42; if (!_Definitely_have_popcnt) { - return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); }); + return _Callback([](_Ty _Val) _STATIC_LAMBDA { return _Popcount_fallback(_Val); }); } #endif // ^^^ !_POPCNT_INTRINSICS_ALWAYS_AVAILABLE ^^^ - return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Unchecked_popcount(_Val); }); + return _Callback([](_Ty _Val) _STATIC_LAMBDA { return _Unchecked_popcount(_Val); }); } #endif // ^^^ _HAS_POPCNT_INTRINSICS ^^^ - return _Callback([](_Ty _Val) _STATIC_CALL_OPERATOR { return _Popcount_fallback(_Val); }); + return _Callback([](_Ty _Val) _STATIC_LAMBDA { return _Popcount_fallback(_Val); }); } #undef _HAS_POPCNT_INTRINSICS diff --git a/stl/inc/__msvc_ranges_to.hpp b/stl/inc/__msvc_ranges_to.hpp index f13f2026a05..768f6e31756 100644 --- a/stl/inc/__msvc_ranges_to.hpp +++ b/stl/inc/__msvc_ranges_to.hpp @@ -1145,7 +1145,7 @@ namespace ranges { "the default-constructed object. (N4981 [range.utility.conv.to]/2.1.5)"); } } else if constexpr (input_range>) { - const auto _Xform = [](auto&& _Elem) _STATIC_CALL_OPERATOR { + const auto _Xform = [](auto&& _Elem) _STATIC_LAMBDA { return _RANGES to>(_STD forward(_Elem)); }; return _RANGES to<_Container>(views::transform(ref_view{_Range}, _Xform), _STD forward<_Types>(_Args)...); diff --git a/stl/inc/__msvc_ranges_tuple_formatter.hpp b/stl/inc/__msvc_ranges_tuple_formatter.hpp index 5d1989e5a66..eeb768995f6 100644 --- a/stl/inc/__msvc_ranges_tuple_formatter.hpp +++ b/stl/inc/__msvc_ranges_tuple_formatter.hpp @@ -241,7 +241,7 @@ class basic_format_arg { template explicit handle(_Ty& _Val) noexcept : _Ptr(_STD addressof(_Val)), _Format([](basic_format_parse_context<_CharType>& _Parse_ctx, - _Context& _Format_ctx, const void* _Ptr) _STATIC_CALL_OPERATOR { + _Context& _Format_ctx, const void* _Ptr) _STATIC_LAMBDA { using _Td = remove_const_t<_Ty>; // doesn't drop const-qualifier per an unnumbered LWG issue using _Tq = conditional_t<_Formattable_with, const _Ty, _Ty>; diff --git a/stl/inc/experimental/filesystem b/stl/inc/experimental/filesystem index 71f762adaad..f8d475a1e92 100644 --- a/stl/inc/experimental/filesystem +++ b/stl/inc/experimental/filesystem @@ -851,7 +851,7 @@ public: path& append(const basic_string<_Elem, _Traits, _Alloc>& _Str0) { // append arbitrary source string string_type _Str(_Str0.size(), L'\0'); // convert _Elem and '/' to '\' - _STD transform(_Str0.begin(), _Str0.end(), _Str.begin(), [](const _Elem _Ch) _STATIC_CALL_OPERATOR { + _STD transform(_Str0.begin(), _Str0.end(), _Str.begin(), [](const _Elem _Ch) _STATIC_LAMBDA { auto _Wch = static_cast(_Ch); if (_Wch == _FS_SLASH) { _Wch = _FS_PREF; diff --git a/stl/inc/functional b/stl/inc/functional index 7ed26be7e7c..33d51be9a3b 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1237,7 +1237,7 @@ _NON_MEMBER_CALL(_FUNCTION_POINTER_DEDUCTION_GUIDE, X1, X2, X3) template struct _Deduce_from_call_operator : _Is_memfunptr<_Call_op>::_Guide_type {}; // N4958 [func.wrap.func.con]/16.1 -#ifdef __cpp_static_call_operator +#if _HAS_CXX23 template struct _Inspect_static_call_operator {}; @@ -1257,7 +1257,7 @@ _NON_MEMBER_CALL(_STATIC_CALL_OPERATOR_GUIDES, , , noexcept) template struct _Deduce_from_call_operator<_Fx, _Call_op, void_t().operator())>> : _Inspect_static_call_operator<_Call_op> {}; // N4958 [func.wrap.func.con]/16.2 -#endif // ^^^ defined(__cpp_static_call_operator) ^^^ +#endif // _HAS_CXX23 template struct _Deduce_signature {}; // can't deduce signature when &_Fx::operator() is missing, inaccessible, or ambiguous diff --git a/stl/inc/memory_resource b/stl/inc/memory_resource index 141524b3b40..59aee2f5fc0 100644 --- a/stl/inc/memory_resource +++ b/stl/inc/memory_resource @@ -553,9 +553,9 @@ namespace pmr { // find the pool from which to allocate a block with size _Bytes and alignment _Align const size_t _Size = (_STD max)(_Bytes + sizeof(void*), _Align); const auto _Log_of_size = static_cast(_Ceiling_of_log_2(_Size)); - return {_STD lower_bound(_Pools.begin(), _Pools.end(), _Log_of_size, - [](const _Pool& _Al, const unsigned char _Log) - _STATIC_CALL_OPERATOR { return _Al._Log_of_size < _Log; }), + return { + _STD lower_bound(_Pools.begin(), _Pools.end(), _Log_of_size, + [](const _Pool& _Al, const unsigned char _Log) _STATIC_LAMBDA { return _Al._Log_of_size < _Log; }), _Log_of_size}; } diff --git a/stl/inc/mutex b/stl/inc/mutex index 0daa8314b5b..6e333716403 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -480,7 +480,7 @@ public: : _MyMutexes(_Mtxes...) {} // construct but don't lock ~scoped_lock() noexcept { - _STD apply([](_Mutexes&... _Mtxes) _STATIC_CALL_OPERATOR { (..., (void) _Mtxes.unlock()); }, _MyMutexes); + _STD apply([](_Mutexes&... _Mtxes) _STATIC_LAMBDA { (..., (void) _Mtxes.unlock()); }, _MyMutexes); } scoped_lock(const scoped_lock&) = delete; diff --git a/stl/inc/ranges b/stl/inc/ranges index 3af972f8847..821e2aad4e4 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -3301,7 +3301,7 @@ namespace ranges { _NODISCARD constexpr decltype(auto) operator*() const { using _Ref = common_reference_t, iter_reference_t<_PatternIter>>; - return _Visit_inner_it<_Ref>([](auto&& _It) _STATIC_CALL_OPERATOR -> _Ref { return *_It; }); + return _Visit_inner_it<_Ref>([](auto&& _It) _STATIC_LAMBDA -> _Ref { return *_It; }); } constexpr _Iterator& operator++() { @@ -7189,14 +7189,13 @@ namespace ranges { noexcept((noexcept(*(_STD declval>&>())) && ...)) /* strengthened */ { return _Tuple_transform( - [](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(*_Itr)) -> decltype(auto) { return *_Itr; }, + [](auto& _Itr) _STATIC_LAMBDA noexcept(noexcept(*_Itr)) -> decltype(auto) { return *_Itr; }, _Current); } - constexpr _Iterator& operator++() noexcept( - noexcept(_Tuple_for_each([](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(++_Itr)) { ++_Itr; }, - _Current))) /* strengthened */ { - _Tuple_for_each([](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(++_Itr)) { ++_Itr; }, _Current); + constexpr _Iterator& operator++() noexcept(noexcept(_Tuple_for_each( + [](auto& _Itr) _STATIC_LAMBDA noexcept(noexcept(++_Itr)) { ++_Itr; }, _Current))) /* strengthened */ { + _Tuple_for_each([](auto& _Itr) _STATIC_LAMBDA noexcept(noexcept(++_Itr)) { ++_Itr; }, _Current); return *this; } @@ -7215,10 +7214,10 @@ namespace ranges { } constexpr _Iterator& operator--() noexcept(noexcept(_Tuple_for_each( - [](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(--_Itr)) { --_Itr; }, _Current))) // strengthened + [](auto& _Itr) _STATIC_LAMBDA noexcept(noexcept(--_Itr)) { --_Itr; }, _Current))) // strengthened requires _All_bidirectional<_IsConst, _ViewTypes...> { - _Tuple_for_each([](auto& _Itr) _STATIC_CALL_OPERATOR noexcept(noexcept(--_Itr)) { --_Itr; }, _Current); + _Tuple_for_each([](auto& _Itr) _STATIC_LAMBDA noexcept(noexcept(--_Itr)) { --_Itr; }, _Current); return *this; } @@ -7439,7 +7438,7 @@ namespace ranges { } } - static constexpr auto _Size_closure = [](auto... _Sizes) _STATIC_CALL_OPERATOR noexcept { + static constexpr auto _Size_closure = [](auto... _Sizes) _STATIC_LAMBDA noexcept { using _Common_unsigned_type = _Make_unsigned_like_t>; return (_RANGES min)({static_cast<_Common_unsigned_type>(_Sizes)...}); }; @@ -8029,7 +8028,7 @@ namespace ranges { _NODISCARD constexpr auto operator*() const { return _RANGES _Tuple_transform( - [](auto& _It) _STATIC_CALL_OPERATOR -> decltype(auto) { return *_It; }, _Current); + [](auto& _It) _STATIC_LAMBDA -> decltype(auto) { return *_It; }, _Current); } constexpr _Iterator& operator++() noexcept(noexcept(++_Current.front())) /* strengthened */ { @@ -8956,7 +8955,7 @@ namespace ranges { _NODISCARD constexpr auto operator*() const { return _RANGES _Tuple_transform( - [](auto& _It) _STATIC_CALL_OPERATOR -> decltype(auto) { return *_It; }, _Current); + [](auto& _It) _STATIC_LAMBDA -> decltype(auto) { return *_It; }, _Current); } constexpr _Iterator& operator++() { diff --git a/stl/inc/xstring b/stl/inc/xstring index e18772035bf..02d8fc784ee 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -1503,7 +1503,7 @@ public: return _Reallocate_grow_by( _Count, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const _Elem* const _Ptr, - const size_type _Count) _STATIC_CALL_OPERATOR { + const size_type _Count) _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Old_size); _Traits::copy(_New_ptr + _Old_size, _Ptr, _Count); _Traits::assign(_New_ptr[_Old_size + _Count], _Elem()); @@ -1530,7 +1530,7 @@ public: return _Reallocate_grow_by( _Count, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Count, - const _Elem _Ch) _STATIC_CALL_OPERATOR { + const _Elem _Ch) _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Old_size); _Traits::assign(_New_ptr + _Old_size, _Count, _Ch); _Traits::assign(_New_ptr[_Old_size + _Count], _Elem()); @@ -1608,7 +1608,7 @@ public: return _Reallocate_for( _Count, - [](_Elem* const _New_ptr, const size_type _Count, const _Elem* const _Ptr) _STATIC_CALL_OPERATOR { + [](_Elem* const _New_ptr, const size_type _Count, const _Elem* const _Ptr) _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Ptr, _Count); _Traits::assign(_New_ptr[_Count], _Elem()); }, @@ -1632,7 +1632,7 @@ public: return _Reallocate_for( _Count, - [](_Elem* const _New_ptr, const size_type _Count, const _Elem _Ch) _STATIC_CALL_OPERATOR { + [](_Elem* const _New_ptr, const size_type _Count, const _Elem _Ch) _STATIC_LAMBDA { _Traits::assign(_New_ptr, _Count, _Ch); _Traits::assign(_New_ptr[_Count], _Elem()); }, @@ -1748,7 +1748,7 @@ public: return _Reallocate_grow_by( _Count, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off, - const _Elem* const _Ptr, const size_type _Count) _STATIC_CALL_OPERATOR { + const _Elem* const _Ptr, const size_type _Count) _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Off); _Traits::copy(_New_ptr + _Off, _Ptr, _Count); _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off, _Old_size - _Off + 1); @@ -1779,7 +1779,7 @@ public: return _Reallocate_grow_by( _Count, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off, - const size_type _Count, const _Elem _Ch) _STATIC_CALL_OPERATOR { + const size_type _Count, const _Elem _Ch) _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Off); _Traits::assign(_New_ptr + _Off, _Count, _Ch); _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off, _Old_size - _Off + 1); @@ -1991,7 +1991,7 @@ public: return _Reallocate_grow_by( _Growth, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off, - const size_type _Nx, const _Elem* const _Ptr, const size_type _Count) _STATIC_CALL_OPERATOR { + const size_type _Nx, const _Elem* const _Ptr, const size_type _Count) _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Off); _Traits::copy(_New_ptr + _Off, _Ptr, _Count); _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off + _Nx, _Old_size - _Nx - _Off + 1); @@ -2031,7 +2031,7 @@ public: return _Reallocate_grow_by( _Count - _Nx, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const size_type _Off, - const size_type _Nx, const size_type _Count, const _Elem _Ch) _STATIC_CALL_OPERATOR { + const size_type _Nx, const size_type _Count, const _Elem _Ch) _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Off); _Traits::assign(_New_ptr + _Off, _Count, _Ch); _Traits::copy(_New_ptr + _Off + _Count, _Old_ptr + _Off + _Nx, _Old_size - _Nx - _Off + 1); @@ -2281,7 +2281,7 @@ public: _Reallocate_grow_by( 1, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size, const _Elem _Ch) - _STATIC_CALL_OPERATOR { + _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Old_size); _Traits::assign(_New_ptr[_Old_size], _Ch); _Traits::assign(_New_ptr[_Old_size + 1], _Elem()); @@ -2381,7 +2381,7 @@ public: if (_Mypair._Myval2._Myres < _New_size) { _Reallocate_grow_by(_New_size - _Mypair._Myval2._Mysize, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size) - _STATIC_CALL_OPERATOR { _Traits::copy(_New_ptr, _Old_ptr, _Old_size + 1); }); + _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Old_size + 1); }); } else { _ASAN_STRING_MODIFY(*this, _Mypair._Myval2._Mysize, _New_size); _Mypair._Myval2._Mysize = _New_size; @@ -2419,7 +2419,7 @@ public: const size_type _Old_size = _Mypair._Myval2._Mysize; _Reallocate_grow_by(_Newcap - _Old_size, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size) - _STATIC_CALL_OPERATOR { _Traits::copy(_New_ptr, _Old_ptr, _Old_size + 1); }); + _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Old_size + 1); }); // `_Reallocate_grow_by` calls `_ASAN_STRING_CREATE` assuming that the string // has size (initialized memory) equal to its new capacity (allocated memory). @@ -2447,7 +2447,7 @@ public: const size_type _Old_size = _Mypair._Myval2._Mysize; _Reallocate_grow_by(_Newcap - _Old_size, [](_Elem* const _New_ptr, const _Elem* const _Old_ptr, const size_type _Old_size) - _STATIC_CALL_OPERATOR { _Traits::copy(_New_ptr, _Old_ptr, _Old_size + 1); }); + _STATIC_LAMBDA { _Traits::copy(_New_ptr, _Old_ptr, _Old_size + 1); }); // `_Reallocate_grow_by` calls `_ASAN_STRING_CREATE` assuming that the string // has size (initialized memory) equal to its new capacity (allocated memory). diff --git a/stl/inc/xutility b/stl/inc/xutility index 0c5c942a29d..0d5b9872e48 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -6179,12 +6179,12 @@ namespace ranges { template _Se, class _Ty, class _Pj = identity> requires indirect_binary_predicate, const _Ty*> _NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj = {}) { - constexpr bool _Elements_are_1_or_2_bytes = sizeof(_Iter_value_t<_It>) <= 2; - constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; + constexpr bool _Elements_are_1_byte = sizeof(_Iter_value_t<_It>) == 1; + constexpr bool _Is_sized = sized_sentinel_for<_Se, _It>; if constexpr (_Vector_alg_in_find_is_safe<_It, _Ty> - && (_Elements_are_1_or_2_bytes ? _Is_sized || same_as<_Se, unreachable_sentinel_t> - : _Is_sized && _USE_STD_VECTOR_ALGORITHMS) + && (_Elements_are_1_byte ? _Is_sized || same_as<_Se, unreachable_sentinel_t> + : _Is_sized && _USE_STD_VECTOR_ALGORITHMS) && same_as<_Pj, identity>) { if (!_STD is_constant_evaluated()) { if (!_STD _Could_compare_equal_to_value_type<_It>(_Val)) { @@ -6202,13 +6202,13 @@ namespace ranges { _Ptr_t _Result; #if _USE_STD_VECTOR_ALGORITHMS if constexpr (_Is_sized) { - // When _Is_sized && _Elements_are_1_or_2_bytes, prefer this over memchr()/wmemchr() for performance + // When _Is_sized && _Elements_are_1_byte, prefer this over memchr() for performance const auto _Last_ptr = _First_ptr + (_Last - _First); _Result = _STD _Find_vectorized(_First_ptr, _Last_ptr, _Val); } else #endif // ^^^ _USE_STD_VECTOR_ALGORITHMS ^^^ { - _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_or_2_bytes); + _STL_INTERNAL_STATIC_ASSERT(_Elements_are_1_byte); size_t _Count; if constexpr (_Is_sized) { _Count = static_cast(_Last - _First); @@ -6216,14 +6216,11 @@ namespace ranges { _Count = SIZE_MAX; } - if constexpr (sizeof(_Iter_value_t<_It>) == 1) { - _Result = - static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); - } else { - _STL_INTERNAL_STATIC_ASSERT(sizeof(_Iter_value_t<_It>) == 2); - _Result = reinterpret_cast<_Ptr_t>(const_cast(_CSTD wmemchr( - reinterpret_cast(_First_ptr), static_cast(_Val), _Count))); - } + // C23 7.27.5.2 "The memchr generic function"/2 says "The implementation shall behave as if + // it reads the characters sequentially and stops as soon as a matching character is found." + // C23 7.32.4.6.9 "The wmemchr generic function"/2 lacks such wording, + // so we don't use wmemchr(), avoiding issues with unreachable_sentinel_t. + _Result = static_cast<_Ptr_t>(_CSTD memchr(_First_ptr, static_cast(_Val), _Count)); if constexpr (_Is_sized) { if (_Result == nullptr) { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 2bd67b707b9..9be20813bdd 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -802,6 +802,8 @@ // copy/move constructors and copy/move assignment operators are not trivial (/Wall) // warning C5246: 'member': the initialization of a subobject should be wrapped in braces (/Wall) // warning C5278: adding a specialization for 'type trait' has undefined behavior +// warning C5280: a static operator '()' requires at least '/std:c++23preview' +// warning C5281: a static lambda requires at least '/std:c++23preview' // warning C6294: Ill-defined for-loop: initial condition does not satisfy test. Loop body not executed #ifndef _STL_DISABLED_WARNINGS @@ -809,7 +811,8 @@ #define _STL_DISABLED_WARNINGS \ 4180 4324 4412 4455 4494 4514 4574 4582 4583 4587 \ 4588 4619 4623 4625 4626 4643 4648 4702 4793 4820 \ - 4868 4988 5026 5027 5045 5220 5246 5278 6294 \ + 4868 4988 5026 5027 5045 5220 5246 5278 5280 5281 \ + 6294 \ _STL_DISABLED_WARNING_C4577 \ _STL_DISABLED_WARNING_C4984 \ _STL_DISABLED_WARNING_C5053 \ @@ -820,6 +823,7 @@ // warning: constexpr if is a C++17 extension [-Wc++17-extensions] // warning: explicit(bool) is a C++20 extension [-Wc++20-extensions] // warning: declaring overloaded 'operator()' as 'static' is a C++23 extension [-Wc++23-extensions] +// warning: static lambdas are a C++23 extension [-Wc++23-extensions] // warning: ignoring __declspec(allocator) because the function return type '%s' is not a pointer or reference type // [-Wignored-attributes] // warning: '#pragma float_control' is not supported on this target - ignored [-Wignored-pragmas] @@ -2010,13 +2014,23 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #define _STL_INTERNAL_STATIC_ASSERT(...) #endif // ^^^ !defined(_ENABLE_STL_INTERNAL_CHECK) ^^^ -#ifdef __cpp_static_call_operator +#ifdef __CUDACC__ // TRANSITION, CUDA 12.4 doesn't have downlevel support for static call operators +#define _STATIC_CALL_OPERATOR +#define _CONST_CALL_OPERATOR const +#define _STATIC_LAMBDA +#elif defined(__clang__) || defined(__EDG__) // no workaround #define _STATIC_CALL_OPERATOR static #define _CONST_CALL_OPERATOR -#else // ^^^ defined(__cpp_static_call_operator) / !defined(__cpp_static_call_operator) vvv +#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 -#endif // ^^^ !defined(__cpp_static_call_operator) ^^^ +#define _STATIC_LAMBDA +#else // TRANSITION, VSO-2383148, fixed in VS 2022 17.14 Preview 3 +#define _STATIC_CALL_OPERATOR static +#define _CONST_CALL_OPERATOR +#define _STATIC_LAMBDA +#endif // ^^^ workaround ^^^ #ifdef __CUDACC__ // TRANSITION, CUDA 12.4 doesn't recognize MSVC __restrict; CUDA __restrict__ is not usable in C++ #define _RESTRICT diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index bbdd8ff2094..41c2daac2f6 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -4481,12 +4481,18 @@ extern "C" { // TRANSITION, ABI: preserved for binary compatibility const void* __stdcall __std_find_trivial_unsized_1(const void* const _First, const uint8_t _Val) noexcept { + // C23 7.27.5.2 "The memchr generic function"/2 says "The implementation shall behave as if + // it reads the characters sequentially and stops as soon as a matching character is found." return memchr(_First, _Val, SIZE_MAX); } // TRANSITION, ABI: preserved for binary compatibility const void* __stdcall __std_find_trivial_unsized_2(const void* const _First, const uint16_t _Val) noexcept { - return wmemchr(static_cast(_First), static_cast(_Val), SIZE_MAX); + // C23 7.27.5.2 "The memchr generic function"/2 says "The implementation shall behave as if + // it reads the characters sequentially and stops as soon as a matching character is found." + // C23 7.32.4.6.9 "The wmemchr generic function"/2 lacks such wording, + // so we don't use wmemchr(), avoiding issues with unreachable_sentinel_t. + return __std_find_trivial_unsized_impl(_First, _Val); } // TRANSITION, ABI: preserved for binary compatibility diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 3fd6165a3c6..d3359a1b79c 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -324,13 +324,8 @@ std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp FAIL # *** MISSING COMPILER FEATURES *** -# P1169R4 static operator() -std/ranges/range.adaptors/range.adaptor.object/range_adaptor_closure.pass.cpp:0 FAIL -std/ranges/range.adaptors/range.adaptor.object/range_adaptor_closure.pass.cpp:1 FAIL -std/thread/futures/futures.task/futures.task.members/ctad.static.compile.pass.cpp:0 FAIL -std/thread/futures/futures.task/futures.task.members/ctad.static.compile.pass.cpp:1 FAIL -std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/ctad.static.compile.pass.cpp:0 FAIL -std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/ctad.static.compile.pass.cpp:1 FAIL + +# None! # *** MISSING LWG ISSUE RESOLUTIONS *** @@ -428,35 +423,6 @@ std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp:1 FAIL std/language.support/support.rtti/type.info/type_info.equal.pass.cpp:0 FAIL std/language.support/support.rtti/type.info/type_info.equal.pass.cpp:1 FAIL -# DevCom-10808176 VSO-2319111 MSVC doesn't properly destroy a loop variable in constant evaluation -# Fixed in VS 2022 17.14 Preview 1. -std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp:0 FAIL -std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp:1 FAIL -std/containers/sequences/vector.bool/construct_iter_iter.pass.cpp:0 FAIL -std/containers/sequences/vector.bool/construct_iter_iter.pass.cpp:1 FAIL -std/containers/sequences/vector.bool/construct_iter_iter_alloc.pass.cpp:0 FAIL -std/containers/sequences/vector.bool/construct_iter_iter_alloc.pass.cpp:1 FAIL -std/containers/sequences/vector.bool/construct_size.pass.cpp:0 FAIL -std/containers/sequences/vector.bool/construct_size.pass.cpp:1 FAIL -std/containers/sequences/vector.bool/construct_size_value.pass.cpp:0 FAIL -std/containers/sequences/vector.bool/construct_size_value.pass.cpp:1 FAIL -std/containers/sequences/vector.bool/construct_size_value_alloc.pass.cpp:0 FAIL -std/containers/sequences/vector.bool/construct_size_value_alloc.pass.cpp:1 FAIL -std/containers/sequences/vector/reverse_iterators.pass.cpp:0 FAIL -std/containers/sequences/vector/reverse_iterators.pass.cpp:1 FAIL -std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp:0 FAIL -std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp:1 FAIL -std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp:0 FAIL -std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp:1 FAIL -std/containers/sequences/vector/vector.cons/construct_size.pass.cpp:0 FAIL -std/containers/sequences/vector/vector.cons/construct_size.pass.cpp:1 FAIL -std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp:0 FAIL -std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp:1 FAIL -std/containers/sequences/vector/vector.cons/construct_size_value_alloc.pass.cpp:0 FAIL -std/containers/sequences/vector/vector.cons/construct_size_value_alloc.pass.cpp:1 FAIL -std/containers/views/mdspan/mdspan/index_operator.pass.cpp:0 FAIL -std/containers/views/mdspan/mdspan/index_operator.pass.cpp:1 FAIL - # VSO-2338829 constexpr error "subtracting pointers to elements of different arrays" in _String_const_iterator::_Verify_offset() std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp:0 FAIL std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp:1 FAIL @@ -587,11 +553,8 @@ std/input.output/syncstream/syncbuf/syncstream.syncbuf.members/emit.pass.cpp FAI # *** VCRUNTIME BUGS *** -# DevCom-10373274 VSO-1824997 "vcruntime nothrow array operator new falls back on the wrong function" -# This passes for the :1 (ASan) configuration, surprisingly. -# Fixed in VS 2022 17.14 Preview 1. -std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp:0 FAIL -std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp:2 FAIL + +# None! # *** CRT BUGS *** @@ -996,10 +959,12 @@ std/containers/sequences/vector/vector.modifiers/destroy_elements.pass.cpp FAIL std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp FAIL std/strings/basic.string/string.modifiers/string_replace/replace_with_range.pass.cpp FAIL std/utilities/charconv/charconv.to.chars/integral.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/op_or_eq.pass.cpp FAIL -std/utilities/template.bitset/bitset.members/right_shift_eq.pass.cpp FAIL + +# Not analyzed, failing due to constexpr step limits. SKIPPED because they occasionally pass in certain configurations. +std/utilities/template.bitset/bitset.members/left_shift_eq.pass.cpp SKIPPED +std/utilities/template.bitset/bitset.members/op_and_eq.pass.cpp SKIPPED +std/utilities/template.bitset/bitset.members/op_or_eq.pass.cpp SKIPPED +std/utilities/template.bitset/bitset.members/right_shift_eq.pass.cpp SKIPPED # Not analyzed. In debug mode, looks like a proxy object unexpectedly exhausts an 80-byte buffer. # In release mode, fails in a later assertion that appears to be testing libc++-specific behavior. @@ -1102,6 +1067,10 @@ std/ranges/range.adaptors/range.join/range.join.iterator/iter.swap.pass.cpp:1 FA std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/compare.pass.cpp:0 FAIL std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/compare.pass.cpp:1 FAIL +# Not analyzed. Likely MSVC constexpr bug, "note: failure was caused by a read of a variable outside its lifetime" +std/containers/views/mdspan/mdspan/index_operator.pass.cpp:0 FAIL +std/containers/views/mdspan/mdspan/index_operator.pass.cpp:1 FAIL + # Not analyzed. SKIPPED because this is x86-specific, fatal error C1060: compiler is out of heap space std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.iterator.pass.cpp:0 SKIPPED std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.iterator.pass.cpp:1 SKIPPED @@ -1295,6 +1264,10 @@ std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cp std/depr/depr.c.headers/stdalign_h.compile.pass.cpp:0 FAIL std/depr/depr.c.headers/stdalign_h.compile.pass.cpp:1 FAIL +# Not analyzed. Probably an MSVC compiler bug, as it rejects `n | negate | negate` while Clang accepts. +std/ranges/range.adaptors/range.adaptor.object/range_adaptor_closure.pass.cpp:0 FAIL +std/ranges/range.adaptors/range.adaptor.object/range_adaptor_closure.pass.cpp:1 FAIL + # *** XFAILS WHICH PASS *** # These tests contain `// XFAIL: msvc` comments, which accurately describe runtime failures for x86 and x64. @@ -1335,6 +1308,7 @@ std/language.support/support.exception/propagation/current_exception.pass.cpp:2 # to silence warnings, but the MSVC-internal test harness doesn't yet parse ADDITIONAL_COMPILE_FLAGS. std/algorithms/alg.modifying.operations/alg.replace/ranges.replace.pass.cpp:9 SKIPPED std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp:9 SKIPPED +std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp:9 SKIPPED std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp:9 SKIPPED std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp:9 SKIPPED std/algorithms/alg.nonmodifying/alg.fold/left_folds.pass.cpp:9 SKIPPED @@ -1382,8 +1356,9 @@ std/containers/sequences/vector/vector.modifiers/assert.push_back.invalidation.p # Listing these on separate lines would allow magic_comments.txt to recognize it. std/containers/sequences/array/assert.iterators.pass.cpp:9 SKIPPED -# These tests emit C5321, which warns when the resolution to core issue 1656 affects a u8 string literal. +# These tests emit C5321, which warns when the resolution to CWG-1656 affects a u8 string literal. # The conformant behavior is opt-in because it can silently change behavior. -# : warning C5321: nonstandard extension used: encoding '\x80' as a multi-byte utf-8 character. Use \u instead for cross platform compatibility or '/Zc:u8EscapeEncoding' to disable the extension. +# warning C5321: nonstandard extension used: encoding '\x80' as a multi-byte utf-8 character. Use \u instead +# for cross platform compatibility or '/Zc:u8EscapeEncoding' to disable the extension. std/utilities/format/format.functions/escaped_output.unicode.pass.cpp:9 SKIPPED std/utilities/format/format.functions/fill.unicode.pass.cpp:9 SKIPPED diff --git a/tests/std/tests/P1169R4_static_call_operator/test.compile.pass.cpp b/tests/std/tests/P1169R4_static_call_operator/test.compile.pass.cpp index ecd82ea1de6..cbc7e268f91 100644 --- a/tests/std/tests/P1169R4_static_call_operator/test.compile.pass.cpp +++ b/tests/std/tests/P1169R4_static_call_operator/test.compile.pass.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifdef __cpp_static_call_operator - #include #include #include @@ -51,5 +49,3 @@ void all_tests() { test_ctad(); test_ctad(); } - -#endif // ^^^ defined(__cpp_static_call_operator) ^^^ diff --git a/tools/scripts/print_failures.py b/tools/scripts/print_failures.py index 8a09e19f3db..801eb5ffd32 100644 --- a/tools/scripts/print_failures.py +++ b/tools/scripts/print_failures.py @@ -21,7 +21,10 @@ for testcase_elem in test_xml.getElementsByTagName("testcase"): for failure_elem in testcase_elem.getElementsByTagName("failure"): print(f"name: {testcase_elem.getAttribute('classname')}") - print(f"output: {failure_elem.firstChild.data}") + if failure_elem.firstChild is None: + print("No output, possibly because this was an XPASS.") + else: + print(f"output: {failure_elem.firstChild.data}") print("==================================================") else: test_log = json.load(file) From dfbe5eaac4701a8b781439938fdc255d547cc7c8 Mon Sep 17 00:00:00 2001 From: Hauke Neitzel Date: Thu, 20 Feb 2025 08:55:20 +0100 Subject: [PATCH 7/7] LWG-3899 co_yielding elements of an lvalue generator is unnecessarily inefficient (#5303) --- stl/inc/generator | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/stl/inc/generator b/stl/inc/generator index 09c16afc339..3374d9bb589 100644 --- a/stl/inc/generator +++ b/stl/inc/generator @@ -286,6 +286,13 @@ namespace _Gen_detail { return _Nested_awaitable{_STD move(_Elem.range)}; } + template + requires same_as<_Yield_t<_Reference_t<_Rty, _Vty>>, _Yielded> + _NODISCARD auto yield_value(_RANGES elements_of&, _Unused> _Elem) noexcept { + using _Nested_awaitable = _Nested_awaitable_provider<_Rty, _Vty, _Alloc>::_Awaitable; + return _Nested_awaitable{_STD move(_Elem.range)}; + } + template <_RANGES input_range _Rng, class _Alloc> requires convertible_to<_RANGES range_reference_t<_Rng>, _Yielded> _NODISCARD auto yield_value(_RANGES elements_of<_Rng, _Alloc> _Elem) {