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

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

Reply via email to