Message ID | 20180705155559.GA21836@redhat.com |
---|---|
State | New |
Headers | show |
Series | PR libstdc++/58265 implement LWG 2063 for COW strings | expand |
On 05/07/18 16:55 +0100, Jonathan Wakely wrote: >For COW strings the default constructor does not allocate when >_GLIBCXX_FULLY_DYNAMIC_STRING == 0, so can be noexcept. The move >constructor and swap do not allocate when the allocators are equal, so >add conditional noexcept using allocator_traits::is_always_equal. > > PR libstdc++/58265 > * include/bits/basic_string.h [!_GLIBCXX_USE_CXX11_ABI] > [_GLIBCXX_FULLY_DYNAMIC_STRING==0] (basic_string::basic_string()): > Add GLIBCXX_NOEXCEPT. > (basic_string::operator=(basic_string&&)): Add _GLIBCXX_NOEXCEPT_IF > to depend on the allocator's is_always_equal property (LWG 2063). > (basic_string::swap(basic_string&)): Likewise. > * include/bits/basic_string.tcc [!_GLIBCXX_USE_CXX11_ABI] > (basic_string::swap(basic_string&)): Likewise. > * testsuite/21_strings/basic_string/allocator/char/move_assign.cc: > Check is_nothrow_move_assignable. > * testsuite/21_strings/basic_string/allocator/wchar_t/move_assign.cc: > Check is_nothrow_move_assignable. > * testsuite/21_strings/basic_string/cons/char/ > noexcept_move_construct.cc: Likewise. > * testsuite/21_strings/basic_string/cons/wchar_t/ > noexcept_move_construct.cc: Likewise. I missed a bit, finished by this patch. With these changes the SSO and COW strings are slightly closer in behaviour, although the COW one is still missing lots of C++11 features (like passing const_iterator instead of iterator) and C++17 features (deduction guides). Tested powerpc64le-linux, committed to trunk. commit 265fc27e34d7fb8fb80653e3f9782c56c70a7ce4 Author: Jonathan Wakely <jwakely@redhat.com> Date: Thu Jul 5 17:08:54 2018 +0100 PR libstdc++/58265 add noexcept to basic_string::assign(basic_string&&) PR libstdc++/58265 * include/bits/basic_string.h [!_GLIBCXX_USE_CXX11_ABI] (basic_string::assign(basic_string&&)): Add conditional noexcept depending on the allocator's is_always_equal property (LWG 2063). * testsuite/21_strings/basic_string/modifiers/assign/char/ move_assign.cc: Check for non-throwing exception specification. * testsuite/21_strings/basic_string/modifiers/assign/wchar_t/ move_assign.cc: Likewise. diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index baad58682b6..2d1b9dc6c29 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -725,7 +725,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 * The contents of @a str are moved into this string (without copying). * @a str is a valid, but unspecified string. **/ - // PR 58265, this should be noexcept. // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2063. Contradictory requirements for string move assignment basic_string& @@ -4275,9 +4274,9 @@ _GLIBCXX_END_NAMESPACE_CXX11 * This function sets this string to the exact contents of @a __str. * @a __str is a valid, but unspecified string. */ - // PR 58265, this should be noexcept. basic_string& assign(basic_string&& __str) + noexcept(allocator_traits<_Alloc>::is_always_equal::value) { this->swap(__str); return *this; diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/move_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/move_assign.cc index e9116b9c0e0..7089fea04c2 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/move_assign.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/char/move_assign.cc @@ -32,6 +32,9 @@ void test01() a.push_back('1'); b.assign(std::move(a)); VERIFY( b.size() == 1 && b[0] == '1' && a.size() == 0 ); + + // True for std::allocator because is_always_equal, but not true in general: + static_assert(noexcept(a.assign(std::move(b))), "lwg 2063"); } int main() diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/move_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/move_assign.cc index 74e342a8ef4..8d394602a9f 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/move_assign.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/wchar_t/move_assign.cc @@ -32,6 +32,9 @@ void test01() a.push_back(L'1'); b.assign(std::move(a)); VERIFY( b.size() == 1 && b[0] == '1' && a.size() == 0 ); + + // True for std::allocator because is_always_equal, but not true in general: + static_assert(noexcept(a.assign(std::move(b))), "lwg 2063"); } int main()
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index a77074da249..baad58682b6 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -3486,6 +3486,7 @@ _GLIBCXX_END_NAMESPACE_CXX11 */ basic_string() #if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 + _GLIBCXX_NOEXCEPT : _M_dataplus(_S_empty_rep()._M_refdata(), _Alloc()) { } #else : _M_dataplus(_S_construct(size_type(), _CharT(), _Alloc()), _Alloc()){ } @@ -3642,7 +3643,7 @@ _GLIBCXX_END_NAMESPACE_CXX11 * @param __str Source string. */ basic_string& - operator=(const basic_string& __str) + operator=(const basic_string& __str) { return this->assign(__str); } /** @@ -3675,9 +3676,9 @@ _GLIBCXX_END_NAMESPACE_CXX11 * The contents of @a str are moved into this string (without copying). * @a str is a valid, but unspecified string. **/ - // PR 58265, this should be noexcept. basic_string& operator=(basic_string&& __str) + _GLIBCXX_NOEXCEPT_IF(allocator_traits<_Alloc>::is_always_equal::value) { // NB: DR 1204. this->swap(__str); @@ -5111,9 +5112,9 @@ _GLIBCXX_END_NAMESPACE_CXX11 * Exchanges the contents of this string with that of @a __s in constant * time. */ - // PR 58265, this should be noexcept. void - swap(basic_string& __s); + swap(basic_string& __s) + _GLIBCXX_NOEXCEPT_IF(allocator_traits<_Alloc>::is_always_equal::value); // String operations: /** diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc index 04b68ca0202..51bbb7bd6a0 100644 --- a/libstdc++-v3/include/bits/basic_string.tcc +++ b/libstdc++-v3/include/bits/basic_string.tcc @@ -967,6 +967,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void basic_string<_CharT, _Traits, _Alloc>:: swap(basic_string& __s) + _GLIBCXX_NOEXCEPT_IF(allocator_traits<_Alloc>::is_always_equal::value) { if (_M_rep()->_M_is_leaked()) _M_rep()->_M_set_sharable(); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc index 1142586a6ea..b0707802971 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc @@ -34,6 +34,9 @@ void test01() typedef propagating_allocator<C, false> alloc_type; typedef std::basic_string<C, traits, alloc_type> test_type; + static_assert(std::is_move_assignable<test_type>::value, ""); + static_assert(!std::is_nothrow_move_assignable<test_type>::value, ""); + test_type v1(alloc_type(1)); v1.assign(1, c); test_type v2(alloc_type(2)); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/move_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/move_assign.cc index 4276fd69ff1..df9be1925ba 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/move_assign.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/move_assign.cc @@ -34,6 +34,9 @@ void test01() typedef propagating_allocator<C, false> alloc_type; typedef std::basic_string<C, traits, alloc_type> test_type; + static_assert(std::is_move_assignable<test_type>::value, ""); + static_assert(!std::is_nothrow_move_assignable<test_type>::value, ""); + test_type v1(alloc_type(1)); v1.assign(1, c); test_type v2(alloc_type(2)); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/noexcept_move_construct.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/noexcept_move_construct.cc index 5d62c95b13c..a068d5afe62 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/noexcept_move_construct.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/noexcept_move_construct.cc @@ -23,4 +23,8 @@ typedef std::string stype; +// True except for COW strings with _GLIBCXX_FULLY_DYNAMIC_STRING: static_assert(std::is_nothrow_move_constructible<stype>::value, "Error"); + +// True for std::allocator because is_always_equal, but not true in general: +static_assert(std::is_nothrow_move_assignable<stype>::value, "lwg 2063"); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/noexcept_move_construct.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/noexcept_move_construct.cc index 60df8cfefa6..660ff7df579 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/noexcept_move_construct.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/noexcept_move_construct.cc @@ -23,4 +23,8 @@ typedef std::wstring wstype; +// True except for COW strings with _GLIBCXX_FULLY_DYNAMIC_STRING: static_assert(std::is_nothrow_move_constructible<wstype>::value, "Error"); + +// True for std::allocator because is_always_equal, but not true in general: +static_assert(std::is_nothrow_move_assignable<wstype>::value, "lwg 2063");