diff mbox series

PR libstdc++/58265 implement LWG 2063 for COW strings

Message ID 20180705155559.GA21836@redhat.com
State New
Headers show
Series PR libstdc++/58265 implement LWG 2063 for COW strings | expand

Commit Message

Jonathan Wakely July 5, 2018, 3:55 p.m. UTC
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.

Tested powerpc64le-linux, committed to trunk.
commit 926b3b642595383cb4abfbeb3586eecc721c1935
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jul 5 15:12:06 2018 +0100

    PR libstdc++/58265 implement LWG 2063 for COW strings
    
    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.

Comments

Jonathan Wakely July 5, 2018, 5:01 p.m. UTC | #1
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 mbox series

Patch

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");