Tested on Linux x86_64 Inconsistency wrt Allocators in basic_string assignment vs. basic_string::assign (LWG2579)
2019-05-09 Nina Dinka Ranns <dinka.ra...@gmail.com> Inconsistency wrt Allocators in basic_string assignment vs. basic_string::assign (LWG2579) * include/bits/basic_string.h: operator=(const basic_string& __str): moved allocator decision from operator= to assign assign(const basic_string& __str): moved allocator decision from operator= to assign * testsuite/21_strings/basic_string/allocator/char/copy_assign.cc: Adding tests * testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc: Adding tests
Index: libstdc++-v3/include/bits/basic_string.h =================================================================== --- libstdc++-v3/include/bits/basic_string.h (revision 270943) +++ libstdc++-v3/include/bits/basic_string.h (working copy) @@ -664,35 +664,6 @@ basic_string& operator=(const basic_string& __str) { -#if __cplusplus >= 201103L - if (_Alloc_traits::_S_propagate_on_copy_assign()) - { - if (!_Alloc_traits::_S_always_equal() && !_M_is_local() - && _M_get_allocator() != __str._M_get_allocator()) - { - // Propagating allocator cannot free existing storage so must - // deallocate it before replacing current allocator. - if (__str.size() <= _S_local_capacity) - { - _M_destroy(_M_allocated_capacity); - _M_data(_M_local_data()); - _M_set_length(0); - } - else - { - const auto __len = __str.size(); - auto __alloc = __str._M_get_allocator(); - // If this allocation throws there are no effects: - auto __ptr = _Alloc_traits::allocate(__alloc, __len + 1); - _M_destroy(_M_allocated_capacity); - _M_data(__ptr); - _M_capacity(__len); - _M_set_length(__len); - } - } - std::__alloc_on_copy(_M_get_allocator(), __str._M_get_allocator()); - } -#endif return this->assign(__str); } @@ -1363,6 +1334,35 @@ basic_string& assign(const basic_string& __str) { +#if __cplusplus >= 201103L + if (_Alloc_traits::_S_propagate_on_copy_assign()) + { + if (!_Alloc_traits::_S_always_equal() && !_M_is_local() + && _M_get_allocator() != __str._M_get_allocator()) + { + // Propagating allocator cannot free existing storage so must + // deallocate it before replacing current allocator. + if (__str.size() <= _S_local_capacity) + { + _M_destroy(_M_allocated_capacity); + _M_data(_M_local_data()); + _M_set_length(0); + } + else + { + const auto __len = __str.size(); + auto __alloc = __str._M_get_allocator(); + // If this allocation throws there are no effects: + auto __ptr = _Alloc_traits::allocate(__alloc, __len + 1); + _M_destroy(_M_allocated_capacity); + _M_data(__ptr); + _M_capacity(__len); + _M_set_length(__len); + } + } + std::__alloc_on_copy(_M_get_allocator(), __str._M_get_allocator()); + } +#endif this->_M_assign(__str); return *this; } Index: libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc =================================================================== --- libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc (revision 270943) +++ libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc (working copy) @@ -133,10 +133,47 @@ VERIFY( v1.get_allocator() == a2 ); } +void test04() +{ + // LWG2579 + typedef propagating_allocator<C, true> alloc_type; + + typedef std::basic_string<C, traits, alloc_type> test_type; + + test_type v1("tralalala",alloc_type(1)); + test_type v2("content", alloc_type(2)); + test_type v3("content2", alloc_type(3)); + + v1.assign(v2); + v3 = v2; + VERIFY(2 == v1.get_allocator().get_personality()); + VERIFY(2 == v3.get_allocator().get_personality()); + +} + +void test05() +{ + // LWG2579 + typedef propagating_allocator<C, false> alloc_type; + + typedef std::basic_string<C, traits, alloc_type> test_type; + + test_type v1("tralalala",alloc_type(1)); + test_type v2("content", alloc_type(2)); + test_type v3("content2", alloc_type(3)); + + v1.assign(v2); + v3 = v2; + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(3 == v3.get_allocator().get_personality()); +} + int main() { test01(); test02(); test03(); + test04(); + test05(); return 0; } Index: libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc =================================================================== --- libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc (revision 270943) +++ libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc (working copy) @@ -133,10 +133,46 @@ VERIFY( v1.get_allocator() == a2 ); } +void test04() +{ + // LWG2579 + typedef propagating_allocator<C, true> alloc_type; + + typedef std::basic_string<C, traits, alloc_type> test_type; + + test_type v1(L"tralalala",alloc_type(1)); + test_type v2(L"content", alloc_type(2)); + test_type v3(L"content2", alloc_type(3)); + + v1.assign(v2); + v3 = v2; + VERIFY(2 == v1.get_allocator().get_personality()); + VERIFY(2 == v3.get_allocator().get_personality()); + +} + +void test05() +{ + // LWG2579 + typedef propagating_allocator<C, false> alloc_type; + + typedef std::basic_string<C, traits, alloc_type> test_type; + + test_type v1(L"tralalala",alloc_type(1)); + test_type v2(L"content", alloc_type(2)); + test_type v3(L"content2", alloc_type(3)); + + v1.assign(v2); + v3 = v2; + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(3 == v3.get_allocator().get_personality()); +} int main() { test01(); test02(); test03(); + test04(); + test05(); return 0; }