From c86e19b864e85d1594ba0055bd1aaa0d4087949e Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Tue, 26 Oct 2021 21:05:30 +0200 Subject: [PATCH 1/7] Fix bugs in std::string * Missing capacity for null terminator * Leaking memor in case of unequal allocators * Not swapping the proxy during swap * swapping data in case of self swap --- stl/inc/xstring | 42 +- .../tests/P0980R1_constexpr_strings/test.cpp | 459 ++++++++++++++++-- 2 files changed, 429 insertions(+), 72 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 344fea2fe69..d439e60e46e 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -292,6 +292,11 @@ public: } static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Primary_char_traits::assign(_Left, _Right); + } +#endif // __cpp_lib_is_constant_evaluated _Left = _Right; } @@ -431,6 +436,11 @@ public: } static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Primary_char_traits::assign(_Left, _Right); + } +#endif // __cpp_lib_is_constant_evaluated _Left = _Right; } @@ -2449,7 +2459,7 @@ private: static constexpr size_t _Memcpy_val_size = sizeof(_Scary_val) - _Memcpy_val_offset; template - using _Is_elem_cptr = bool_constant<_Is_any_of_v<_Iter, const _Elem* const, _Elem* const, const _Elem*, _Elem*>>; + static constexpr bool _Is_elem_cptr = _Is_any_of_v<_Iter, const _Elem* const, _Elem* const, const _Elem*, _Elem*>; #if _HAS_CXX17 template @@ -2783,10 +2793,7 @@ public: _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal())); _Tidy_init(); } -#endif // _HAS_CXX20 -public: -#if _HAS_CXX20 _NODISCARD bool _Move_assign_from_buffer(_Elem* const _Right, const size_type _Size, const size_type _Res) { // Move assign from a buffer, used exclusively by basic_stringbuf; returns _Large_string_engaged() _Tidy_deallocate(); @@ -2845,9 +2852,6 @@ public: // intentionally slams into noexcept on OOM, TRANSITION, VSO-466800 _Mypair._Myval2._Orphan_all(); _Mypair._Myval2._Reload_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Al), _GET_PROXY_ALLOCATOR(_Alty, _Right_al)); - _Pocma(_Al, _Right_al); - _Take_contents(_Right); - return *this; } } else if constexpr (_Pocma_val == _Pocma_values::_No_propagate_allocators) { if (_Al != _Right_al) { @@ -2859,7 +2863,6 @@ public: _Tidy_deallocate(); _Pocma(_Al, _Right_al); _Take_contents(_Right); - return *this; } @@ -2870,7 +2873,7 @@ public: private: void _Memcpy_val_from(const basic_string& _Right) noexcept { - _STL_INTERNAL_CHECK(_Can_memcpy_val); // TRANSITION, if constexpr + _STL_INTERNAL_CHECK(_Can_memcpy_val); const auto _My_data_mem = reinterpret_cast(_STD addressof(_Mypair._Myval2)) + _Memcpy_val_offset; const auto _Right_data_mem = @@ -3057,11 +3060,10 @@ public: const auto _New_size = _Right._Mypair._Myval2._Mysize; const auto _New_capacity = _Calculate_growth(_New_size, 0, _Right.max_size()); auto _Right_al_non_const = _Right_al; - const auto _New_ptr = _Right_al_non_const.allocate(_New_capacity); // throws + const auto _New_ptr = _Right_al_non_const.allocate(_New_capacity + 1); // throws #if _HAS_CXX20 - if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to - // avoid UB + if (_STD is_constant_evaluated()) { // Begin the lifetimes of the objects before copying to avoid UB _Traits::assign(_Unfancy(_New_ptr), _New_size + 1, _Elem()); } #endif // _HAS_CXX20 @@ -3211,7 +3213,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr::value) { + if constexpr (_Is_elem_cptr) { return append(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { const basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3295,7 +3297,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr::value) { + if constexpr (_Is_elem_cptr) { return assign(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3447,7 +3449,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr::value) { + if constexpr (_Is_elem_cptr) { insert(_Off, _UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { const basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3712,7 +3714,7 @@ public: _Adl_verify_range(_First2, _Last2); const auto _UFirst2 = _Get_unwrapped(_First2); const auto _ULast2 = _Get_unwrapped(_Last2); - if constexpr (_Is_elem_cptr::value) { + if constexpr (_Is_elem_cptr) { return replace(_Off, _Length, _UFirst2, _Convert_size(static_cast(_ULast2 - _UFirst2))); } else { const basic_string _Right(_UFirst2, _ULast2, get_allocator()); @@ -4110,13 +4112,11 @@ public: _Right._Mypair._Myval2._Orphan_all(); } - if (_My_large || _Right_large) { - _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); - } + _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); #endif // _ITERATOR_DEBUG_LEVEL != 0 - } - _Swap_data(_Right); + _Swap_data(_Right); + } } #if _HAS_CXX17 diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index fe89c11e21c..fd7b9df359c 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -85,6 +85,11 @@ constexpr auto get_cat() { } } +template +constexpr auto get_cat_view() { + return basic_string_view{get_cat()}; +} + template constexpr auto get_dog() { if constexpr (is_same_v) { @@ -102,6 +107,11 @@ constexpr auto get_dog() { } } +template +constexpr auto get_dog_view() { + return basic_string_view{get_dog()}; +} + template constexpr auto get_no_needle() { if constexpr (is_same_v) { @@ -165,9 +175,72 @@ constexpr bool equalRanges(const Range1& range1, const Range2& range2) noexcept #endif // !__cpp_lib_concepts } +template +class MyAlloc { +private: + size_t _id; + + [[nodiscard]] constexpr size_t equal_id() const noexcept { + if constexpr (is_always_equal::value) { + return 10; + } else { + return _id; + } + } + +public: + [[nodiscard]] constexpr size_t id() const noexcept { + return _id; + } + + using value_type = CharType; + + using propagate_on_container_copy_assignment = POCCA; + using propagate_on_container_move_assignment = POCMA; + using propagate_on_container_swap = POCS; + using is_always_equal = EQUAL; + + constexpr explicit MyAlloc(const size_t off) : _id(off) {} + + template + constexpr MyAlloc(const MyAlloc& other) noexcept : _id(other.id()) {} + + template + [[nodiscard]] constexpr bool operator==(const MyAlloc& other) const noexcept { + return equal_id() == other.equal_id(); + } + + template + [[nodiscard]] constexpr bool operator!=(const MyAlloc& other) const noexcept { + return equal_id() != other.equal_id(); + } + + [[nodiscard]] constexpr CharType* allocate(const size_t numElements) { + return allocator{}.allocate(numElements + equal_id()) + equal_id(); + } + + constexpr void deallocate(CharType* const first, const size_t numElements) noexcept { + allocator{}.deallocate(first - equal_id(), numElements + equal_id()); + } +}; + +template +using StationaryAlloc = MyAlloc; +template +using CopyAlloc = MyAlloc; +template +using CopyEqualAlloc = MyAlloc; +template +using MoveAlloc = MyAlloc; +template +using MoveEqualAlloc = MyAlloc; +template +using SwapAlloc = MyAlloc; +template +using SwapEqualAlloc = MyAlloc; + template constexpr bool test_interface() { -#ifndef __EDG__ // TRANSITION, VSO-1273296 using str = basic_string; { // constructors @@ -1021,6 +1094,10 @@ constexpr bool test_interface() { resized.resize(6, CharType{'a'}); assert(equalRanges(resized, "Helaaa"sv)); + + // ensure we grow properly from small string + resized.resize(26, CharType{'a'}); + assert(equalRanges(resized, "Helaaaaaaaaaaaaaaaaaaaaaaa"sv)); } { // swap @@ -1506,12 +1583,11 @@ constexpr bool test_interface() { basic_string_view sv = s; assert(equalRanges(sv, "Hello fluffy kittens"sv)); } -#endif // __EDG__ + return true; } constexpr bool test_udls() { -#ifndef __EDG__ // TRANSITION, VSO-1273296 assert(equalRanges("purr purr"s, "purr purr"sv)); #ifdef __cpp_char8_t assert(equalRanges(u8"purr purr"s, "purr purr"sv)); @@ -1519,7 +1595,7 @@ constexpr bool test_udls() { assert(equalRanges(u"purr purr"s, "purr purr"sv)); assert(equalRanges(U"purr purr"s, "purr purr"sv)); assert(equalRanges(L"purr purr"s, "purr purr"sv)); -#endif // __EDG__ + return true; } @@ -1532,7 +1608,6 @@ struct CharLikeType { template constexpr bool test_iterators() { -#ifndef __EDG__ // TRANSITION, VSO-1273296 using str = basic_string; str literal_constructed = get_literal_input(); @@ -1546,6 +1621,7 @@ constexpr bool test_iterators() { cit = cit2; } +#if defined(MSVC_INTERNAL_TESTING) || defined(__clang__) // TRANSITION, VSO-1270433 { // op-> basic_string> bs{CharType{'x'}}; auto it = bs.begin(); @@ -1556,6 +1632,7 @@ constexpr bool test_iterators() { auto cc = cit->c; assert(cc == CharType{'x'}); } +#endif // defined(MSVC_INTERNAL_TESTING) || defined(__clang__) { // increment auto it = literal_constructed.begin(); @@ -1647,14 +1724,13 @@ constexpr bool test_iterators() { const auto cit = literal_constructed.cbegin() + 2; assert(cit[2] == CharType{'l'}); } -#endif // __EDG__ + return true; } template constexpr bool test_growth() { using str = basic_string; -#ifndef __EDG__ // TRANSITION, VSO-1273296 { str v(1007, CharType{'a'}); @@ -1754,60 +1830,341 @@ constexpr bool test_growth() { assert(v.capacity() == 8015); } } -#endif // __EDG__ + return true; } -int main() { - test_interface(); -#ifdef __cpp_char8_t - test_interface(); -#endif // __cpp_char8_t - test_interface(); - test_interface(); - test_interface(); +template +constexpr void test_copy_ctor() { + using Str = basic_string, StationaryAlloc>; + + { // Allocated + Str range_constructed(get_view_input(), StationaryAlloc{11}); + Str copy_constructed(range_constructed); + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == 11); + assert(copy_constructed.get_allocator().id() == 11); + } - test_udls(); + { // SSO + Str range_constructed_sso(get_cat_view(), StationaryAlloc{11}); + Str copy_constructed_sso(range_constructed_sso); + assert(equalRanges(range_constructed_sso, get_cat_view())); + assert(equalRanges(copy_constructed_sso, get_cat_view())); + assert(range_constructed_sso.get_allocator().id() == 11); + assert(copy_constructed_sso.get_allocator().id() == 11); + } +} - test_iterators(); -#ifdef __cpp_char8_t - test_iterators(); -#endif // __cpp_char8_t - test_iterators(); - test_iterators(); - test_iterators(); +template +constexpr void test_copy_alloc_ctor(const size_t id1, const size_t id2) { + using Str = basic_string, StationaryAlloc>; + + { // Allocated + Str range_constructed(get_view_input(), StationaryAlloc{id1}); + Str copy_constructed(range_constructed, StationaryAlloc{id2}); + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_constructed.get_allocator().id() == id2); + } - test_growth(); -#ifdef __cpp_char8_t - test_growth(); -#endif // __cpp_char8_t - test_growth(); - test_growth(); - test_growth(); + { // SSO + Str range_constructed_sso(get_cat_view(), StationaryAlloc{id1}); + Str copy_constructed_sso(range_constructed_sso, StationaryAlloc{id2}); + assert(equalRanges(range_constructed_sso, get_cat_view())); + assert(equalRanges(copy_constructed_sso, get_cat_view())); + assert(range_constructed_sso.get_allocator().id() == id1); + assert(copy_constructed_sso.get_allocator().id() == id2); + } +} - static_assert(test_interface()); -#ifdef __cpp_char8_t - static_assert(test_interface()); -#endif // __cpp_char8_t - static_assert(test_interface()); - static_assert(test_interface()); - static_assert(test_interface()); +template +constexpr void test_copy_assign(const size_t id1, const size_t id2, const size_t id3) { + using Str = basic_string, Alloc>; - static_assert(test_udls()); + { // Allocated to SSO + Str range_constructed(get_view_input(), Alloc{id1}); + Str copy_assigned(get_cat_view(), Alloc{id2}); - static_assert(test_iterators()); -#ifdef __cpp_char8_t - static_assert(test_iterators()); -#endif // __cpp_char8_t - static_assert(test_iterators()); - static_assert(test_iterators()); - static_assert(test_iterators()); + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } + + { // SSO to SSO + Str range_constructed(get_dog_view(), Alloc{id1}); + Str copy_assigned(get_cat_view(), Alloc{id2}); + + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_dog_view())); + assert(equalRanges(copy_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } - static_assert(test_growth()); + { // SSO to Allocated + Str range_constructed(get_dog_view(), Alloc{id1}); + Str copy_assigned(get_view_input(), Alloc{id2}); + + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_dog_view())); + assert(equalRanges(copy_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } + + { // Allocated to Allocated + Str range_constructed(get_view_input(), Alloc{id1}); + Str copy_assigned(get_view_input(), Alloc{id2}); + copy_assigned.resize(30, 'a'); + + copy_assigned = range_constructed; + assert(equalRanges(range_constructed, get_view_input())); + assert(equalRanges(copy_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(copy_assigned.get_allocator().id() == id3); + } +} + +template +constexpr void test_move_ctor() { + using Str = basic_string, StationaryAlloc>; + + { // Allocated + // Iterators are taken over if the containers are equal + Str range_constructed(get_view_input(), StationaryAlloc{11}); + const auto test_it = range_constructed.begin(); + Str move_constructed(move(range_constructed)); + + assert(test_it == move_constructed.begin()); + assert(range_constructed.empty()); + assert(equalRanges(move_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == 11); + assert(move_constructed.get_allocator().id() == 11); + } + + { // SSO + Str range_constructed(get_cat_view(), StationaryAlloc{11}); + Str move_constructed(move(range_constructed)); + + assert(range_constructed.empty()); + assert(equalRanges(move_constructed, get_cat_view())); + assert(range_constructed.get_allocator().id() == 11); + assert(move_constructed.get_allocator().id() == 11); + } +} + +template +constexpr void test_move_alloc_ctor(const size_t id1, const size_t id2) { + using Str = basic_string, StationaryAlloc>; + + { // Allocated + // Iterators are taken over if the containers are equal + Str range_constructed(get_view_input(), StationaryAlloc{id1}); + const auto test_it = range_constructed.begin(); + Str move_constructed(move(range_constructed), StationaryAlloc{id2}); + + assert(id1 != id2 || test_it == move_constructed.begin()); + assert((id1 == id2) == range_constructed.empty()); + assert(equalRanges(move_constructed, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_constructed.get_allocator().id() == id2); + } + + { // SSO + Str range_constructed(get_cat_view(), StationaryAlloc{id1}); + Str move_constructed(move(range_constructed), StationaryAlloc{id2}); + + assert((id1 == id2) == range_constructed.empty()); + assert(equalRanges(move_constructed, get_cat_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_constructed.get_allocator().id() == id2); + } +} + +template +constexpr void test_move_assign(const size_t id1, const size_t id2, const size_t id3) { + using Str = basic_string, Alloc>; + // Iterators are taken over if the containers are equal + + { // Allocated to SSO + Str range_constructed(get_view_input(), Alloc{id1}); + const auto test_it = range_constructed.begin(); + Str move_assigned(get_cat_view(), Alloc{id2}); + + move_assigned = move(range_constructed); + assert(id1 != id3 || test_it == move_assigned.begin()); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } + + { // SSO to SSO + Str range_constructed(get_dog_view(), Alloc{id1}); + Str move_assigned(get_cat_view(), Alloc{id2}); + + move_assigned = move(range_constructed); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } + + { // SSO to Allocated + Str range_constructed(get_dog_view(), Alloc{id1}); + Str move_assigned(get_view_input(), Alloc{id2}); + + move_assigned = move(range_constructed); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_dog_view())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } + + { // Allocated to Allocated + Str range_constructed(get_view_input(), Alloc{id1}); + Str move_assigned(get_view_input(), Alloc{id2}); + move_assigned.resize(30, 'a'); + const auto test_it = range_constructed.begin(); + + move_assigned = move(range_constructed); + assert(id1 != id3 || test_it == move_assigned.begin()); + assert((id1 == id3) == range_constructed.empty()); + assert(equalRanges(move_assigned, get_view_input())); + assert(range_constructed.get_allocator().id() == id1); + assert(move_assigned.get_allocator().id() == id3); + } +} + +template +constexpr void test_swap(const size_t id1, const size_t id2) { + using Str = basic_string, Alloc>; + { // Allocated to SSO + Str lhs(get_view_input(), Alloc{id1}); + Str rhs(get_cat_view(), Alloc{id2}); + const auto lhs_begin = lhs.begin(); + + lhs.swap(rhs); + assert(lhs_begin == rhs.begin()); + + assert(equalRanges(lhs, get_cat_view())); + assert(equalRanges(rhs, get_view_input())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } + + { // SSO to SSO + Str lhs(get_dog_view(), Alloc{id1}); + Str rhs(get_cat_view(), Alloc{id2}); + + lhs.swap(rhs); + assert(equalRanges(lhs, get_cat_view())); + assert(equalRanges(rhs, get_dog_view())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } + + { // SSO to Allocated + Str lhs(get_dog_view(), Alloc{id1}); + Str rhs(get_view_input(), Alloc{id2}); + const auto rhs_begin = rhs.begin(); + + lhs.swap(rhs); + assert(rhs_begin == lhs.begin()); + + assert(equalRanges(lhs, get_view_input())); + assert(equalRanges(rhs, get_dog_view())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } + + { // Allocated to Allocated + Str lhs(get_view_input(), Alloc{id1}); + Str rhs(get_view_input(), Alloc{id2}); + rhs.resize(30, 'a'); + const auto lhs_begin = lhs.begin(); + const auto rhs_begin = rhs.begin(); + + Str expected_lhs = rhs; + + lhs.swap(rhs); + assert(lhs_begin == rhs.begin()); + assert(rhs_begin == lhs.begin()); + + assert(equalRanges(lhs, expected_lhs)); + assert(equalRanges(rhs, get_view_input())); + + assert(lhs.get_allocator().id() == id2); + assert(rhs.get_allocator().id() == id1); + } +} + +template +constexpr bool test_allocator_awareness() { + test_copy_ctor(); + test_copy_alloc_ctor(11, 11); // equal allocators + test_copy_alloc_ctor(11, 22); // non-equal allocators + test_copy_assign>(11, 11, 11); // non-POCCA, equal allocators + test_copy_assign>(11, 22, 22); // non-POCCA, non-equal allocators + test_copy_assign>(11, 11, 11); // POCCA, equal allocators + test_copy_assign>(11, 22, 11); // POCCA, non-equal allocators + test_copy_assign>(11, 22, 11); // POCCA, always-equal allocators + + test_move_ctor(); + test_move_alloc_ctor(11, 11); // equal allocators + test_move_alloc_ctor(11, 22); // non-equal allocators + + test_move_assign>(11, 11, 11); // non-POCMA, equal allocators + test_move_assign>(11, 22, 22); // non-POCMA, non-equal allocators + test_move_assign>(11, 11, 11); // POCMA, equal allocators + test_move_assign>(11, 22, 11); // POCMA, non-equal allocators + test_move_assign>(11, 22, 11); // POCMA, always-equal allocators + + test_swap>(11, 11); // non-POCS, equal allocators + // UNDEFINED BEHAVIOR, NOT TESTED - non-POCS, non-equal allocators + test_swap>(11, 11); // POCS, equal allocators + test_swap>(11, 22); // POCS, non-equal allocators + test_swap>(11, 22); // POCS, always-equal allocators + + return true; +} + +template +constexpr bool test_all() { + test_interface(); + test_iterators(); + test_growth(); + test_allocator_awareness(); + +#ifndef __EDG__ // TRANSITION, VSO-1273296 + static_assert(test_interface()); + static_assert(test_iterators()); + static_assert(test_growth()); + static_assert(test_allocator_awareness()); +#endif // __EDG__ + + return true; +} + +int main() { + test_all(); #ifdef __cpp_char8_t - static_assert(test_growth()); + test_all(); #endif // __cpp_char8_t - static_assert(test_growth()); - static_assert(test_growth()); - static_assert(test_growth()); + test_all(); + test_all(); + test_all(); + + test_udls(); +#ifndef __EDG__ // TRANSITION, VSO-1273296 + static_assert(test_udls()); +#endif // __EDG__ } From a6b80c2df2384e664022f37443634cf9cf63a52f Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Wed, 27 Oct 2021 12:01:30 +0200 Subject: [PATCH 2/7] Apply review comments --- stl/inc/xstring | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index d439e60e46e..8d8fe106da8 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2459,7 +2459,7 @@ private: static constexpr size_t _Memcpy_val_size = sizeof(_Scary_val) - _Memcpy_val_offset; template - static constexpr bool _Is_elem_cptr = _Is_any_of_v<_Iter, const _Elem* const, _Elem* const, const _Elem*, _Elem*>; + static constexpr bool _Is_elem_cptr_v = _Is_any_of_v<_Iter, const _Elem* const, _Elem* const, const _Elem*, _Elem*>; #if _HAS_CXX17 template @@ -3213,7 +3213,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr) { + if constexpr (_Is_elem_cptr_v) { return append(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { const basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3297,7 +3297,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr) { + if constexpr (_Is_elem_cptr_v) { return assign(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3449,7 +3449,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr) { + if constexpr (_Is_elem_cptr_v) { insert(_Off, _UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { const basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3714,7 +3714,7 @@ public: _Adl_verify_range(_First2, _Last2); const auto _UFirst2 = _Get_unwrapped(_First2); const auto _ULast2 = _Get_unwrapped(_Last2); - if constexpr (_Is_elem_cptr) { + if constexpr (_Is_elem_cptr_v) { return replace(_Off, _Length, _UFirst2, _Convert_size(static_cast(_ULast2 - _UFirst2))); } else { const basic_string _Right(_UFirst2, _ULast2, get_allocator()); From 468c14e34bc58671b5a29f453f2c34a7a2b84578 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 26 Nov 2021 11:48:16 +0100 Subject: [PATCH 3/7] Address review comments --- .../std/tests/P0980R1_constexpr_strings/test.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index fd7b9df359c..e60893a3cd0 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -210,11 +210,6 @@ class MyAlloc { return equal_id() == other.equal_id(); } - template - [[nodiscard]] constexpr bool operator!=(const MyAlloc& other) const noexcept { - return equal_id() != other.equal_id(); - } - [[nodiscard]] constexpr CharType* allocate(const size_t numElements) { return allocator{}.allocate(numElements + equal_id()) + equal_id(); } @@ -1935,7 +1930,7 @@ constexpr void test_move_ctor() { using Str = basic_string, StationaryAlloc>; { // Allocated - // Iterators are taken over if the containers are equal + // Iterators are taken over if the allocators are equal and source is large Str range_constructed(get_view_input(), StationaryAlloc{11}); const auto test_it = range_constructed.begin(); Str move_constructed(move(range_constructed)); @@ -1963,7 +1958,7 @@ constexpr void test_move_alloc_ctor(const size_t id1, const size_t id2) { using Str = basic_string, StationaryAlloc>; { // Allocated - // Iterators are taken over if the containers are equal + // Iterators are taken over if the allocators are equal and source is large Str range_constructed(get_view_input(), StationaryAlloc{id1}); const auto test_it = range_constructed.begin(); Str move_constructed(move(range_constructed), StationaryAlloc{id2}); @@ -1989,7 +1984,7 @@ constexpr void test_move_alloc_ctor(const size_t id1, const size_t id2) { template constexpr void test_move_assign(const size_t id1, const size_t id2, const size_t id3) { using Str = basic_string, Alloc>; - // Iterators are taken over if the containers are equal + // Iterators are taken over if the allocators are equal and source is large { // Allocated to SSO Str range_constructed(get_view_input(), Alloc{id1}); @@ -2138,7 +2133,7 @@ constexpr bool test_allocator_awareness() { } template -constexpr bool test_all() { +constexpr void test_all() { test_interface(); test_iterators(); test_growth(); @@ -2150,8 +2145,6 @@ constexpr bool test_all() { static_assert(test_growth()); static_assert(test_allocator_awareness()); #endif // __EDG__ - - return true; } int main() { From 7d0989cdc115d0a11b0189898844e71f4dba177d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 14 Dec 2021 19:05:09 -0800 Subject: [PATCH 4/7] Fine-grained EDG workarounds. Also change the MSVC internal testing guard to EDG. (As an aside, that internal macro was recently underscore-prefixed.) --- .../tests/P0980R1_constexpr_strings/test.cpp | 144 +++++++++++++++++- 1 file changed, 138 insertions(+), 6 deletions(-) diff --git a/tests/std/tests/P0980R1_constexpr_strings/test.cpp b/tests/std/tests/P0980R1_constexpr_strings/test.cpp index 185bb163b74..4781b71f252 100644 --- a/tests/std/tests/P0980R1_constexpr_strings/test.cpp +++ b/tests/std/tests/P0980R1_constexpr_strings/test.cpp @@ -238,6 +238,9 @@ template constexpr bool test_interface() { using str = basic_string; +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // constructors // range constructors str literal_constructed{get_literal_input()}; @@ -293,6 +296,9 @@ constexpr bool test_interface() { assert(equalRanges(conversion_start_length_constructed, "llo"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // allocator constructors allocator alloc; @@ -341,6 +347,9 @@ constexpr bool test_interface() { assert(equalRanges(conversion_start_length_constructed, "llo"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // assignment operator str literal_constructed = get_literal_input(); @@ -371,6 +380,9 @@ constexpr bool test_interface() { assert(equalRanges(conversion_assigned, literal_constructed)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // assign str literal_constructed = get_literal_input(); @@ -487,6 +499,9 @@ constexpr bool test_interface() { assert(char_traits::length(cs) == literal_constructed.size()); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // iterators str literal_constructed = get_literal_input(); const str const_literal_constructed = get_literal_input(); @@ -618,6 +633,9 @@ constexpr bool test_interface() { assert(cleared.capacity() == str{get_literal_input()}.capacity()); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // insert str insert_char = get_literal_input(); const CharType to_be_inserted = CharType{','}; @@ -695,6 +713,9 @@ constexpr bool test_interface() { assert(equalRanges(insert_iter_count_char, "Hellooooo fluffy kittens"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // erase str erase_pos_count = get_literal_input(); erase_pos_count.erase(0, 6); @@ -741,6 +762,9 @@ constexpr bool test_interface() { assert(pushed.back() == CharType{'y'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // append const str literal_constructed = get_literal_input(); @@ -786,6 +810,9 @@ constexpr bool test_interface() { assert(equalRanges(append_conversion_start_length, "bbllo"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // operator+= str literal_constructed = get_literal_input(); @@ -811,6 +838,9 @@ constexpr bool test_interface() { assert(equalRanges(plus_conversion, "bbHello fluffy kittens"sv)); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // compare const str first = get_literal_input(); const str second = get_cat(); @@ -925,6 +955,9 @@ constexpr bool test_interface() { assert(comp_pos_count_conversion_pos_count_greater == 1); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // starts_with const str starts = get_literal_input(); const str input_string_true = starts.substr(0, 5); @@ -940,6 +973,9 @@ constexpr bool test_interface() { assert(!input_string_false.starts_with(get_literal_input())); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // ends_with const str ends = get_literal_input(); const str input_string_true = ends.substr(5); @@ -956,6 +992,9 @@ constexpr bool test_interface() { } #if _HAS_CXX23 +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // contains const str hello_fluffy_kittens = get_literal_input(); // "Hello fluffy kittens" constexpr auto kitten_ptr = get_cat(); // "kitten" @@ -971,6 +1010,9 @@ constexpr bool test_interface() { } #endif // _HAS_CXX23 +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // replace const str input = get_dog(); @@ -1060,6 +1102,9 @@ constexpr bool test_interface() { assert(equalRanges(replaced_pos_count_conversion_pos_count, "dfluffy"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // substr const str input = get_literal_input(); @@ -1082,6 +1127,9 @@ constexpr bool test_interface() { assert(equalRanges(copy_count_pos, "fluffy"sv)); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // resize str resized = get_literal_input(); resized.resize(3); @@ -1096,6 +1144,9 @@ constexpr bool test_interface() { } #if _HAS_CXX23 +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // resize_and_overwrite constexpr basic_string_view hello_fluffy_kittens = get_view_input(); constexpr basic_string_view hello = hello_fluffy_kittens.substr(0, 5); @@ -1212,6 +1263,9 @@ constexpr bool test_interface() { assert(equalRanges(first, expected_second)); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // find const str input = get_literal_input(); const str needle = get_cat(); @@ -1270,6 +1324,9 @@ constexpr bool test_interface() { assert(find_convertible_pos == str::npos); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // rfind const str input = get_literal_input(); const str needle = get_cat(); @@ -1556,6 +1613,9 @@ constexpr bool test_interface() { assert(find_last_not_of_convertible_pos == str::npos); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // operator+ const str first = get_cat(); const str second = get_dog(); @@ -1597,6 +1657,9 @@ constexpr bool test_interface() { assert(equalRanges(op_char_rstr, "!dog"sv)); } +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // comparison str first(get_view_input()); str second(get_view_input()); @@ -1685,6 +1748,12 @@ constexpr bool test_interface() { } constexpr bool test_udls() { +#ifdef __EDG__ // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return true; + } +#endif // ^^^ workaround ^^^ + assert(equalRanges("purr purr"s, "purr purr"sv)); #ifdef __cpp_char8_t assert(equalRanges(u8"purr purr"s, "purr purr"sv)); @@ -1718,7 +1787,9 @@ constexpr bool test_iterators() { cit = cit2; } -#if defined(MSVC_INTERNAL_TESTING) || defined(__clang__) // TRANSITION, VSO-1270433 +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // op-> basic_string> bs{CharType{'x'}}; auto it = bs.begin(); @@ -1729,8 +1800,10 @@ constexpr bool test_iterators() { auto cc = cit->c; assert(cc == CharType{'x'}); } -#endif // defined(MSVC_INTERNAL_TESTING) || defined(__clang__) +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // increment auto it = literal_constructed.begin(); assert(*++it == CharType{'e'}); @@ -1743,6 +1816,9 @@ constexpr bool test_iterators() { assert(*cit == CharType{'l'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // advance auto it = literal_constructed.begin() + 2; assert(*it == CharType{'l'}); @@ -1759,6 +1835,9 @@ constexpr bool test_iterators() { assert(*cit == CharType{'f'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // decrement auto it = literal_constructed.end(); assert(*--it == CharType{'s'}); @@ -1771,6 +1850,9 @@ constexpr bool test_iterators() { assert(*cit == CharType{'n'}); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // advance back auto it = literal_constructed.end() - 2; assert(*it == CharType{'n'}); @@ -1813,6 +1895,9 @@ constexpr bool test_iterators() { assert((it3 <=> it1) == strong_ordering::greater); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // access const auto it = literal_constructed.begin() + 2; it[2] = CharType{'l'}; @@ -1868,6 +1953,9 @@ constexpr bool test_growth() { assert(v.capacity() == 1510); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1882,6 +1970,9 @@ constexpr bool test_growth() { assert(v.capacity() == 1510); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1900,6 +1991,9 @@ constexpr bool test_growth() { } } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1912,6 +2006,9 @@ constexpr bool test_growth() { assert(v.capacity() == 1510); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { str v(1007, CharType{'a'}); @@ -1933,6 +2030,12 @@ constexpr bool test_growth() { template constexpr void test_copy_ctor() { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + using Str = basic_string, StationaryAlloc>; { // Allocated @@ -1956,6 +2059,12 @@ constexpr void test_copy_ctor() { template constexpr void test_copy_alloc_ctor(const size_t id1, const size_t id2) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + using Str = basic_string, StationaryAlloc>; { // Allocated @@ -1979,6 +2088,12 @@ constexpr void test_copy_alloc_ctor(const size_t id1, const size_t id2) { template constexpr void test_copy_assign(const size_t id1, const size_t id2, const size_t id3) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + using Str = basic_string, Alloc>; { // Allocated to SSO @@ -2029,6 +2144,12 @@ constexpr void test_copy_assign(const size_t id1, const size_t id2, const size_t template constexpr void test_move_ctor() { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + using Str = basic_string, StationaryAlloc>; { // Allocated @@ -2057,6 +2178,12 @@ constexpr void test_move_ctor() { template constexpr void test_move_alloc_ctor(const size_t id1, const size_t id2) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + using Str = basic_string, StationaryAlloc>; { // Allocated @@ -2085,6 +2212,12 @@ constexpr void test_move_alloc_ctor(const size_t id1, const size_t id2) { template constexpr void test_move_assign(const size_t id1, const size_t id2, const size_t id3) { +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (is_constant_evaluated()) { + return; + } +#endif // ^^^ workaround ^^^ + using Str = basic_string, Alloc>; // Iterators are taken over if the allocators are equal and source is large @@ -2183,6 +2316,9 @@ constexpr void test_swap(const size_t id1, const size_t id2) { assert(rhs.get_allocator().id() == id1); } +#if defined(__EDG__) && _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, VSO-1273296 + if (!is_constant_evaluated()) +#endif // ^^^ workaround ^^^ { // Allocated to Allocated Str lhs(get_view_input(), Alloc{id1}); Str rhs(get_view_input(), Alloc{id2}); @@ -2241,12 +2377,10 @@ constexpr void test_all() { test_growth(); test_allocator_awareness(); -#ifndef __EDG__ // TRANSITION, VSO-1273296 static_assert(test_interface()); static_assert(test_iterators()); static_assert(test_growth()); static_assert(test_allocator_awareness()); -#endif // __EDG__ } int main() { @@ -2259,7 +2393,5 @@ int main() { test_all(); test_udls(); -#ifndef __EDG__ // TRANSITION, VSO-1273296 static_assert(test_udls()); -#endif // __EDG__ } From 617caebceee18506e124969dec264923742107ec Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 14 Dec 2021 20:06:55 -0800 Subject: [PATCH 5/7] After GH 2064, we guard `is_constant_evaluated` with `_HAS_CXX20`. --- stl/inc/xstring | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 3fcd9d9e5f5..d78f82c5f3f 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -292,11 +292,11 @@ public: } static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { -#ifdef __cpp_lib_is_constant_evaluated +#if _HAS_CXX20 if (_STD is_constant_evaluated()) { return _Primary_char_traits::assign(_Left, _Right); } -#endif // __cpp_lib_is_constant_evaluated +#endif // _HAS_CXX20 _Left = _Right; } @@ -436,11 +436,11 @@ public: } static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept { -#ifdef __cpp_lib_is_constant_evaluated +#if _HAS_CXX20 if (_STD is_constant_evaluated()) { return _Primary_char_traits::assign(_Left, _Right); } -#endif // __cpp_lib_is_constant_evaluated +#endif // _HAS_CXX20 _Left = _Right; } From f8c3c32f5ca7991148b9f021d5bb863258b2d321 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 14 Dec 2021 21:01:53 -0800 Subject: [PATCH 6/7] Cleanup: Use _My_data/_Right_data, inline _My_large/_Right_large. --- stl/inc/xstring | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index d78f82c5f3f..74722a3e960 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -4116,17 +4116,18 @@ public: _Pocs(_Getal(), _Right._Getal()); #if _ITERATOR_DEBUG_LEVEL != 0 - const bool _My_large = _Mypair._Myval2._Large_string_engaged(); - const bool _Right_large = _Right._Mypair._Myval2._Large_string_engaged(); - if (!_My_large) { - _Mypair._Myval2._Orphan_all(); + auto& _My_data = _Mypair._Myval2; + auto& _Right_data = _Right._Mypair._Myval2; + + if (!_My_data._Large_string_engaged()) { + _My_data._Orphan_all(); } - if (!_Right_large) { - _Right._Mypair._Myval2._Orphan_all(); + if (!_Right_data._Large_string_engaged()) { + _Right_data._Orphan_all(); } - _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); + _My_data._Swap_proxy_and_iterators(_Right_data); #endif // _ITERATOR_DEBUG_LEVEL != 0 _Swap_data(_Right); From 68d7023630a7334972398fb2bd71b00fbe20dd7f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 15 Dec 2021 00:52:59 -0800 Subject: [PATCH 7/7] Revert `_Is_elem_cptr_v` due to `/clr:pure` failures. test.obj : fatal error LNK1179: invalid or corrupt file: duplicate COMDAT '???__E??$_Is_elem_cptr_v@QB_W@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@$$Q0_NB@?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@YMXXZ@?A0xd54b7a0b@@$$FYMXXZ' --- stl/inc/xstring | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/xstring b/stl/inc/xstring index 74722a3e960..b98faf0abf1 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2453,7 +2453,7 @@ private: static constexpr size_t _Memcpy_val_size = sizeof(_Scary_val) - _Memcpy_val_offset; template - static constexpr bool _Is_elem_cptr_v = _Is_any_of_v<_Iter, const _Elem* const, _Elem* const, const _Elem*, _Elem*>; + using _Is_elem_cptr = bool_constant<_Is_any_of_v<_Iter, const _Elem* const, _Elem* const, const _Elem*, _Elem*>>; #if _HAS_CXX17 template @@ -3208,7 +3208,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr_v) { + if constexpr (_Is_elem_cptr::value) { return append(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { const basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3292,7 +3292,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr_v) { + if constexpr (_Is_elem_cptr::value) { return assign(_UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3444,7 +3444,7 @@ public: _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); - if constexpr (_Is_elem_cptr_v) { + if constexpr (_Is_elem_cptr::value) { insert(_Off, _UFirst, _Convert_size(static_cast(_ULast - _UFirst))); } else { const basic_string _Right(_UFirst, _ULast, get_allocator()); @@ -3709,7 +3709,7 @@ public: _Adl_verify_range(_First2, _Last2); const auto _UFirst2 = _Get_unwrapped(_First2); const auto _ULast2 = _Get_unwrapped(_Last2); - if constexpr (_Is_elem_cptr_v) { + if constexpr (_Is_elem_cptr::value) { return replace(_Off, _Length, _UFirst2, _Convert_size(static_cast(_ULast2 - _UFirst2))); } else { const basic_string _Right(_UFirst2, _ULast2, get_allocator());