commit cdf98fe7aeb8f7815daed0d30709395ef2d34d7a Author: Jonathan Wakely Date: Thu Jul 5 12:09:48 2018 +0100 PR libstdc++/85831 define move constructors and operators for exceptions PR libstdc++/85831 * config/abi/pre/gnu.ver: Export move constructors and move assignment operators for std::logic_error and std::runtime_error. * include/std/stdexcept: Use _GLIBCXX_NOTHROW instead of _GLIBCXX_USE_NOEXCEPT. (logic_error, runtime_error): Declare move constructors and move assignment operators. When not declared already, define copy constructors and copy assignment operators as explicit-defaulted. (domain_error, invalid_argument, length_error, out_of_range) (overflow_error, underflow_error): Define move constructors and move assignment operators as explicitly-defaulted. * libsupc++/exception.h (exception): Likewise. * src/c++11/cow-stdexcept.cc (logic_error, runtime_error): Define move constructors and move assignment operators as defaulted. * testsuite/19_diagnostics/stdexcept.cc: Check that constructors and assignment operators are defined. diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 782b1238742..521cebf1f80 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -2014,6 +2014,13 @@ GLIBCXX_3.4.26 { # std::basic_string::insert(const_iterator, initializer_list) _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE6insertEN9__gnu_cxx17__normal_iteratorIPK[cw]S4_EESt16initializer_listI[cw]E; + # std::logic_error move operations + _ZNSt11logic_errorC[12]EOS_; + _ZNSt11logic_erroraSEOS_; + # std::runtime_error move operations + _ZNSt13runtime_errorC[12]EOS_; + _ZNSt13runtime_erroraSEOS_; + } GLIBCXX_3.4.25; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/std/stdexcept b/libstdc++-v3/include/std/stdexcept index 5267e5692bf..4fcc719f005 100644 --- a/libstdc++-v3/include/std/stdexcept +++ b/libstdc++-v3/include/std/stdexcept @@ -55,8 +55,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __cow_string(); __cow_string(const std::string&); __cow_string(const char*, size_t); - __cow_string(const __cow_string&) _GLIBCXX_USE_NOEXCEPT; - __cow_string& operator=(const __cow_string&) _GLIBCXX_USE_NOEXCEPT; + __cow_string(const __cow_string&) _GLIBCXX_NOTHROW; + __cow_string& operator=(const __cow_string&) _GLIBCXX_NOTHROW; ~__cow_string(); #if __cplusplus >= 201103L __cow_string(__cow_string&&) noexcept; @@ -83,7 +83,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION char _M_bytes[sizeof(__str)]; }; - __sso_string() _GLIBCXX_USE_NOEXCEPT; + __sso_string() _GLIBCXX_NOTHROW; __sso_string(const std::string&); __sso_string(const char*, size_t); __sso_string(const __sso_string&); @@ -122,19 +122,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201103L explicit logic_error(const char*) _GLIBCXX_TXN_SAFE; + + logic_error(logic_error&&) noexcept; + logic_error& operator=(logic_error&&) noexcept; #endif #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_DEFINE_STDEXCEPT_COPY_OPS - logic_error(const logic_error&) _GLIBCXX_USE_NOEXCEPT; - logic_error& operator=(const logic_error&) _GLIBCXX_USE_NOEXCEPT; + logic_error(const logic_error&) _GLIBCXX_NOTHROW; + logic_error& operator=(const logic_error&) _GLIBCXX_NOTHROW; +#elif __cplusplus >= 201103L + logic_error(const logic_error&) = default; + logic_error& operator=(const logic_error&) = default; #endif - virtual ~logic_error() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT; + virtual ~logic_error() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW; /** Returns a C-style character string describing the general cause of * the current error (the same string passed to the ctor). */ virtual const char* - what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT; + what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW; # ifdef _GLIBCXX_TM_TS_INTERNAL friend void* @@ -152,8 +158,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit domain_error(const char*) _GLIBCXX_TXN_SAFE; domain_error(const domain_error&) = default; domain_error& operator=(const domain_error&) = default; + domain_error(domain_error&&) = default; + domain_error& operator=(domain_error&&) = default; #endif - virtual ~domain_error() _GLIBCXX_USE_NOEXCEPT; + virtual ~domain_error() _GLIBCXX_NOTHROW; }; /** Thrown to report invalid arguments to functions. */ @@ -165,8 +173,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit invalid_argument(const char*) _GLIBCXX_TXN_SAFE; invalid_argument(const invalid_argument&) = default; invalid_argument& operator=(const invalid_argument&) = default; + invalid_argument(invalid_argument&&) = default; + invalid_argument& operator=(invalid_argument&&) = default; #endif - virtual ~invalid_argument() _GLIBCXX_USE_NOEXCEPT; + virtual ~invalid_argument() _GLIBCXX_NOTHROW; }; /** Thrown when an object is constructed that would exceed its maximum @@ -179,8 +189,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit length_error(const char*) _GLIBCXX_TXN_SAFE; length_error(const length_error&) = default; length_error& operator=(const length_error&) = default; + length_error(length_error&&) = default; + length_error& operator=(length_error&&) = default; #endif - virtual ~length_error() _GLIBCXX_USE_NOEXCEPT; + virtual ~length_error() _GLIBCXX_NOTHROW; }; /** This represents an argument whose value is not within the expected @@ -193,8 +205,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit out_of_range(const char*) _GLIBCXX_TXN_SAFE; out_of_range(const out_of_range&) = default; out_of_range& operator=(const out_of_range&) = default; + out_of_range(out_of_range&&) = default; + out_of_range& operator=(out_of_range&&) = default; #endif - virtual ~out_of_range() _GLIBCXX_USE_NOEXCEPT; + virtual ~out_of_range() _GLIBCXX_NOTHROW; }; /** Runtime errors represent problems outside the scope of a program; @@ -214,19 +228,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus >= 201103L explicit runtime_error(const char*) _GLIBCXX_TXN_SAFE; + + runtime_error(runtime_error&&) noexcept; + runtime_error& operator=(runtime_error&&) noexcept; #endif #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_DEFINE_STDEXCEPT_COPY_OPS - runtime_error(const runtime_error&) _GLIBCXX_USE_NOEXCEPT; - runtime_error& operator=(const runtime_error&) _GLIBCXX_USE_NOEXCEPT; + runtime_error(const runtime_error&) _GLIBCXX_NOTHROW; + runtime_error& operator=(const runtime_error&) _GLIBCXX_NOTHROW; +#elif __cplusplus >= 201103L + runtime_error(const runtime_error&) = default; + runtime_error& operator=(const runtime_error&) = default; #endif - virtual ~runtime_error() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT; + virtual ~runtime_error() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW; /** Returns a C-style character string describing the general cause of * the current error (the same string passed to the ctor). */ virtual const char* - what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT; + what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW; # ifdef _GLIBCXX_TM_TS_INTERNAL friend void* @@ -243,8 +263,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit range_error(const char*) _GLIBCXX_TXN_SAFE; range_error(const range_error&) = default; range_error& operator=(const range_error&) = default; + range_error(range_error&&) = default; + range_error& operator=(range_error&&) = default; #endif - virtual ~range_error() _GLIBCXX_USE_NOEXCEPT; + virtual ~range_error() _GLIBCXX_NOTHROW; }; /** Thrown to indicate arithmetic overflow. */ @@ -256,8 +278,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit overflow_error(const char*) _GLIBCXX_TXN_SAFE; overflow_error(const overflow_error&) = default; overflow_error& operator=(const overflow_error&) = default; + overflow_error(overflow_error&&) = default; + overflow_error& operator=(overflow_error&&) = default; #endif - virtual ~overflow_error() _GLIBCXX_USE_NOEXCEPT; + virtual ~overflow_error() _GLIBCXX_NOTHROW; }; /** Thrown to indicate arithmetic underflow. */ @@ -269,8 +293,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit underflow_error(const char*) _GLIBCXX_TXN_SAFE; underflow_error(const underflow_error&) = default; underflow_error& operator=(const underflow_error&) = default; + underflow_error(underflow_error&&) = default; + underflow_error& operator=(underflow_error&&) = default; #endif - virtual ~underflow_error() _GLIBCXX_USE_NOEXCEPT; + virtual ~underflow_error() _GLIBCXX_NOTHROW; }; // @} group exceptions diff --git a/libstdc++-v3/libsupc++/exception.h b/libstdc++-v3/libsupc++/exception.h index 1adfe7cbef6..426fba22a57 100644 --- a/libstdc++-v3/libsupc++/exception.h +++ b/libstdc++-v3/libsupc++/exception.h @@ -60,17 +60,19 @@ namespace std class exception { public: - exception() _GLIBCXX_USE_NOEXCEPT { } - virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT; + exception() _GLIBCXX_NOTHROW { } + virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW; #if __cplusplus >= 201103L exception(const exception&) = default; exception& operator=(const exception&) = default; + exception(exception&&) = default; + exception& operator=(exception&&) = default; #endif /** Returns a C-style character string describing the general cause * of the current error. */ virtual const char* - what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT; + what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW; }; } // namespace std diff --git a/libstdc++-v3/src/c++11/cow-stdexcept.cc b/libstdc++-v3/src/c++11/cow-stdexcept.cc index 5ad3d94ae31..a2df7892fd4 100644 --- a/libstdc++-v3/src/c++11/cow-stdexcept.cc +++ b/libstdc++-v3/src/c++11/cow-stdexcept.cc @@ -53,7 +53,10 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - // Copy constructors and assignment operators defined using COW std::string + // Copy/move constructors and assignment operators defined using COW string. + // These operations are noexcept even though copying a COW string is not, + // but we know that the string member in an exception has not been "leaked" + // so copying is a simple reference count increment. logic_error::logic_error(const logic_error& e) noexcept : exception(e), _M_msg(e._M_msg) { } @@ -61,6 +64,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION logic_error& logic_error::operator=(const logic_error& e) noexcept { _M_msg = e._M_msg; return *this; } + logic_error::logic_error(logic_error&& e) noexcept = default; + + logic_error& + logic_error::operator=(logic_error&& e) noexcept = default; + runtime_error::runtime_error(const runtime_error& e) noexcept : exception(e), _M_msg(e._M_msg) { } @@ -68,6 +76,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION runtime_error::operator=(const runtime_error& e) noexcept { _M_msg = e._M_msg; return *this; } + runtime_error::runtime_error(runtime_error&& e) noexcept = default; + + runtime_error& + runtime_error::operator=(runtime_error&& e) noexcept = default; + // New C++11 constructors: logic_error::logic_error(const char* __arg) diff --git a/libstdc++-v3/testsuite/19_diagnostics/stdexcept.cc b/libstdc++-v3/testsuite/19_diagnostics/stdexcept.cc index 82351118733..87d111dddef 100644 --- a/libstdc++-v3/testsuite/19_diagnostics/stdexcept.cc +++ b/libstdc++-v3/testsuite/19_diagnostics/stdexcept.cc @@ -219,9 +219,37 @@ void test02() } } +void test03() +{ + std::logic_error le1(""); + // Copy constructor: + std::logic_error le2(le1); + // Copy assignment operator: + le1 = le2; +#if __cplusplus >= 201103L + // Move constructor: + std::logic_error le3 = std::move(le1); + // Move assignment operator: + le1 = std::move(le3); +#endif + + std::runtime_error re1(""); + // Copy constructor: + std::runtime_error re2(re1); + // Copy assignment operator: + re1 = re2; +#if __cplusplus >= 201103L + // Move constructor: + std::runtime_error re3 = std::move(re1); + // Move assignment operator: + re1 = std::move(re3); +#endif +} + int main(void) { test01(); test02(); + test03(); return 0; }