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 <jwak...@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()