Index: libcxx/include/exception =================================================================== --- libcxx/include/exception +++ libcxx/include/exception @@ -141,16 +141,72 @@ #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. +#ifndef _LIBCPP_EXCEPTION_PTR_GNU_INLINE +#if !__has_attribute(__gnu_inline__) +#error "this compiler does not appear to support the __gnu_inline__ attribute!" +#endif + +#ifndef __GLIBCXX__ +#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_; + +#ifndef __GLIBCXX__ + void __incr_refcount() _NOEXCEPT; + void __decr_refcount() _NOEXCEPT; +#endif + 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; + } + + // Move assignment is not available for the glibcxx ABI because it + // doesn't have __decr_refcount(). +#ifndef __GLIBCXX__ + _LIBCPP_INLINE_VISIBILITY exception_ptr& operator=(exception_ptr&& __rhs) _NOEXCEPT { + if (__ptr_ != nullptr) + __decr_refcount(); + __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 +223,44 @@ friend _LIBCPP_FUNC_VIS void rethrow_exception(exception_ptr); }; +// If __GLIBCXX__ is defined, the exception_ptr from libsupc++ is used (which +// works because it happens to have the same layout as our exception_ptr). +// The constructor, assignment operator, and destructor should just delegate +// to the libsupc++ implementations then, so we don't provide definitions for +// them here. +#ifndef __GLIBCXX__ +_LIBCPP_EXCEPTION_PTR_GNU_INLINE +exception_ptr::exception_ptr(const exception_ptr& __rhs) _NOEXCEPT : __ptr_(__rhs.__ptr_) { + if (__rhs.__ptr_ != nullptr) + __incr_refcount(); +} + +_LIBCPP_EXCEPTION_PTR_GNU_INLINE +exception_ptr& exception_ptr::operator=(const exception_ptr& __rhs) _NOEXCEPT { + if (__ptr_ != __rhs.__ptr_) { + if (__ptr_ != nullptr) + __decr_refcount(); + __ptr_ = __rhs.__ptr_; + if (__ptr_ != nullptr) + __incr_refcount(); + } + return *this; +} + +_LIBCPP_EXCEPTION_PTR_GNU_INLINE +exception_ptr::~exception_ptr() _NOEXCEPT { + if (__ptr_ != nullptr) + __decr_refcount(); +} +#endif // __GLIBCXX__ + +_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,15 @@ namespace std { -exception_ptr::~exception_ptr() noexcept { +void exception_ptr::__decr_refcount() noexcept { __cxa_decrement_exception_refcount(__ptr_); } -exception_ptr::exception_ptr(const exception_ptr& other) noexcept - : __ptr_(other.__ptr_) +void exception_ptr::__incr_refcount() noexcept { __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()) { Index: libcxx/src/support/runtime/exception_pointer_unimplemented.ipp =================================================================== --- libcxx/src/support/runtime/exception_pointer_unimplemented.ipp +++ libcxx/src/support/runtime/exception_pointer_unimplemented.ipp @@ -12,22 +12,14 @@ namespace std { -exception_ptr::~exception_ptr() noexcept +void exception_ptr::__decr_refcount() noexcept { # warning exception_ptr not yet implemented fprintf(stderr, "exception_ptr not yet implemented\n"); ::abort(); } -exception_ptr::exception_ptr(const exception_ptr& other) noexcept - : __ptr_(other.__ptr_) -{ -# warning exception_ptr not yet implemented - fprintf(stderr, "exception_ptr not yet implemented\n"); - ::abort(); -} - -exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept +void exception_ptr::__incr_refcount() noexcept { # warning exception_ptr not yet implemented fprintf(stderr, "exception_ptr not yet implemented\n");