Index: libcxx/include/exception =================================================================== --- libcxx/include/exception +++ libcxx/include/exception @@ -141,16 +141,77 @@ #ifndef _LIBCPP_ABI_MICROSOFT +// Previously, the copy constructor, assignment operator, and destructor of +// exception_ptr were defined out-of-line, which prevented useful compiler +// optimizations (especially for the case where the exception_ptr is known to +// be empty). Changing the out-of-line definitions to inline definitions is an +// ABI break, however; to prevent this, we have to make sure the symbols +// remain available in the libc++ library, in addition to being defined inline +// here in this header. To this end, we use the __gnu_inline__ attribute via the +// _LIBCPP_EXCEPTION_PTR_GNU_INLINE macro: The macro is defined as empty in +// src/exception.cpp, forcing the definitions of the aforementioned functions to +// be emitted and included in the library. When users of libc++ (re)compile their +// code, however, the _LIBCPP_EXCEPTION_PTR_GNU_INLINE macro won't be defined, +// and thus the __gnu_inline__ attribute will suppress generation of these +// functions while making their definitions available for inlining. + +// We only enable the optimization if we have known support for it from the ABI side: +#if defined(_LIBCPP_ABI_VERSION) || defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI) +#define _LIBCPP_EXCEPTION_PTR_INCR_DECR + +extern "C" { +extern void __cxa_increment_exception_refcount(void *) _NOEXCEPT; +extern void __cxa_decrement_exception_refcount(void *) _NOEXCEPT; +} +#endif + +#ifndef _LIBCPP_EXCEPTION_PTR_GNU_INLINE +#if !__has_attribute(__gnu_inline__) +#error "this compiler does not appear to support the __gnu_inline__ attribute!" +#endif + +#ifdef _LIBCPP_EXCEPTION_PTR_INCR_DECR +#define _LIBCPP_EXCEPTION_PTR_GNU_INLINE __attribute__((__gnu_inline__)) inline +#else +#define _LIBCPP_EXCEPTION_PTR_GNU_INLINE /*empty*/ +#endif +#endif + + +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgnu-inline-cpp-without-extern") + class _LIBCPP_TYPE_VIS exception_ptr { void* __ptr_; + public: _LIBCPP_INLINE_VISIBILITY exception_ptr() _NOEXCEPT : __ptr_() {} _LIBCPP_INLINE_VISIBILITY exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {} - exception_ptr(const exception_ptr&) _NOEXCEPT; - exception_ptr& operator=(const exception_ptr&) _NOEXCEPT; - ~exception_ptr() _NOEXCEPT; + _LIBCPP_EXCEPTION_PTR_GNU_INLINE exception_ptr(const exception_ptr&) _NOEXCEPT; + _LIBCPP_EXCEPTION_PTR_GNU_INLINE exception_ptr& operator=(const exception_ptr&) _NOEXCEPT; + _LIBCPP_EXCEPTION_PTR_GNU_INLINE ~exception_ptr() _NOEXCEPT; + + _LIBCPP_INLINE_VISIBILITY exception_ptr(exception_ptr&& __rhs) _NOEXCEPT : __ptr_(__rhs.__ptr_) { + __rhs.__ptr_ = nullptr; + } + +#ifdef _LIBCPP_EXCEPTION_PTR_INCR_DECR + _LIBCPP_INLINE_VISIBILITY exception_ptr& operator=(exception_ptr&& __rhs) _NOEXCEPT { + if (__ptr_ != nullptr) + __cxa_decrement_exception_refcount(__ptr_); + __ptr_ = __rhs.__ptr_; + __rhs.__ptr_ = nullptr; + return *this; + } +#endif + + _LIBCPP_INLINE_VISIBILITY void swap(exception_ptr& __rhs) _NOEXCEPT { + void *__tmp = __ptr_; + __ptr_ = __rhs.__ptr_; + __rhs.__ptr_ = __tmp; + } _LIBCPP_INLINE_VISIBILITY explicit operator bool() const _NOEXCEPT {return __ptr_ != nullptr;} @@ -167,6 +228,43 @@ friend _LIBCPP_FUNC_VIS void rethrow_exception(exception_ptr); }; +// If _LIBCPP_EXCEPTION_PTR_INCR_DECR is not defined, either the exception_ptr from +// libsupc++ is used or the required functionality is unimplemented and calling any +// of these functions will abort. In either case, we don't provide definitions here +// but delegate to the implementations in libcxx/src/support/runtime/. +#ifdef _LIBCPP_EXCEPTION_PTR_INCR_DECR +_LIBCPP_EXCEPTION_PTR_GNU_INLINE +exception_ptr::exception_ptr(const exception_ptr& __rhs) _NOEXCEPT : __ptr_(__rhs.__ptr_) { + if (__ptr_ != nullptr) + __cxa_increment_exception_refcount(__ptr_); +} + +_LIBCPP_EXCEPTION_PTR_GNU_INLINE +exception_ptr& exception_ptr::operator=(const exception_ptr& __rhs) _NOEXCEPT { + if (__ptr_ != __rhs.__ptr_) { + if (__ptr_ != nullptr) + __cxa_decrement_exception_refcount(__ptr_); + __ptr_ = __rhs.__ptr_; + if (__ptr_ != nullptr) + __cxa_increment_exception_refcount(__ptr_); + } + return *this; +} + +_LIBCPP_EXCEPTION_PTR_GNU_INLINE +exception_ptr::~exception_ptr() _NOEXCEPT { + if (__ptr_ != nullptr) + __cxa_decrement_exception_refcount(__ptr_); +} +#endif // _LIBCPP_EXCEPTION_PTR_INCR_DECR + +_LIBCPP_DIAGNOSTIC_POP // pops CLANG_DIAGNOSTIC_IGNORED("-Wgnu-inline-cpp-without-extern") + +inline _LIBCPP_INLINE_VISIBILITY void +swap(exception_ptr& __lhs, exception_ptr& __rhs) _NOEXCEPT { + __lhs.swap(__rhs); +} + template _LIBCPP_INLINE_VISIBILITY exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT Index: libcxx/src/exception.cpp =================================================================== --- libcxx/src/exception.cpp +++ libcxx/src/exception.cpp @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// +#define _LIBCPP_EXCEPTION_PTR_GNU_INLINE /*empty*/ #include + #include #include Index: libcxx/src/support/runtime/exception_pointer_cxxabi.ipp =================================================================== --- libcxx/src/support/runtime/exception_pointer_cxxabi.ipp +++ libcxx/src/support/runtime/exception_pointer_cxxabi.ipp @@ -13,27 +13,6 @@ namespace std { -exception_ptr::~exception_ptr() noexcept { - __cxa_decrement_exception_refcount(__ptr_); -} - -exception_ptr::exception_ptr(const exception_ptr& other) noexcept - : __ptr_(other.__ptr_) -{ - __cxa_increment_exception_refcount(__ptr_); -} - -exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept -{ - if (__ptr_ != other.__ptr_) - { - __cxa_increment_exception_refcount(other.__ptr_); - __cxa_decrement_exception_refcount(__ptr_); - __ptr_ = other.__ptr_; - } - return *this; -} - nested_exception::nested_exception() noexcept : __ptr_(current_exception()) {