diff --git a/stl/inc/exception b/stl/inc/exception index 7804935aeb..4b4101af0a 100644 --- a/stl/inc/exception +++ b/stl/inc/exception @@ -1,442 +1,443 @@ -// exception standard header - -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef _EXCEPTION_ -#define _EXCEPTION_ -#include -#if _STL_COMPILER_PREPROCESSOR - -#include -#include - -#pragma pack(push, _CRT_PACKING) -#pragma warning(push, _STL_WARNING_LEVEL) -#pragma warning(disable : _STL_DISABLED_WARNINGS) -_STL_DISABLE_CLANG_WARNINGS -#pragma push_macro("new") -#undef new - -_STD_BEGIN - -#if _HAS_DEPRECATED_UNCAUGHT_EXCEPTION -_EXPORT_STD extern "C++" _CXX17_DEPRECATE_UNCAUGHT_EXCEPTION _NODISCARD _CRTIMP2_PURE bool - __CLRCALL_PURE_OR_CDECL uncaught_exception() noexcept; -#endif // _HAS_DEPRECATED_UNCAUGHT_EXCEPTION -_EXPORT_STD extern "C++" _NODISCARD _CRTIMP2_PURE int __CLRCALL_PURE_OR_CDECL uncaught_exceptions() noexcept; - -_STD_END - -#if _HAS_EXCEPTIONS - -#include // TRANSITION, VSO-2048380: This is unnecessary, but many projects assume it as of 2024-04-29 -#include - -_STD_BEGIN - -_EXPORT_STD using ::terminate; - -#ifndef _M_CEE_PURE -_EXPORT_STD using ::set_terminate; -_EXPORT_STD using ::terminate_handler; - -_EXPORT_STD _NODISCARD inline terminate_handler __CRTDECL get_terminate() noexcept { - // get current terminate handler - return _get_terminate(); -} -#endif // !defined(_M_CEE_PURE) - -#if _HAS_UNEXPECTED -using ::unexpected; - -#ifndef _M_CEE_PURE -using ::set_unexpected; -using ::unexpected_handler; - -_NODISCARD inline unexpected_handler __CRTDECL get_unexpected() noexcept { - // get current unexpected handler - return _get_unexpected(); -} -#endif // !defined(_M_CEE_PURE) -#endif // _HAS_UNEXPECTED - -_STD_END - -#else // ^^^ _HAS_EXCEPTIONS / !_HAS_EXCEPTIONS vvv - -#pragma push_macro("stdext") -#undef stdext - -#define _STDEXT_BEGIN \ - _EXTERN_CXX_WORKAROUND \ - namespace stdext { - -#define _STDEXT_END \ - } \ - _END_EXTERN_CXX_WORKAROUND - -#define _STDEXT ::stdext:: - -_STDEXT_BEGIN -class _NODISCARD exception; -_STDEXT_END - -_STD_BEGIN - -_EXPORT_STD using _STDEXT exception; - -using _Prhand = void(__cdecl*)(const exception&); - -extern _CRTIMP2_PURE_IMPORT _Prhand _Raise_handler; // pointer to raise handler - -_STD_END - -_STDEXT_BEGIN -class _NODISCARD exception { // base of all library exceptions -public: - static _STD _Prhand _Set_raise_handler(_STD _Prhand _Pnew) { // register a handler for _Raise calls - const _STD _Prhand _Pold = _STD _Raise_handler; - _STD _Raise_handler = _Pnew; - return _Pold; - } - - // this constructor is necessary to compile - // successfully header new for _HAS_EXCEPTIONS==0 scenario - explicit __CLR_OR_THIS_CALL exception(const char* _Message = "unknown", int = 1) noexcept : _Ptr(_Message) {} - - __CLR_OR_THIS_CALL exception(const exception& _Right) noexcept : _Ptr(_Right._Ptr) {} - - exception& __CLR_OR_THIS_CALL operator=(const exception& _Right) noexcept { - _Ptr = _Right._Ptr; - return *this; - } - - virtual __CLR_OR_THIS_CALL ~exception() noexcept {} - - _NODISCARD virtual const char* __CLR_OR_THIS_CALL what() const noexcept { // return pointer to message string - return _Ptr ? _Ptr : "unknown exception"; - } - - [[noreturn]] void __CLR_OR_THIS_CALL _Raise() const { // raise the exception - if (_STD _Raise_handler) { - (*_STD _Raise_handler)(*this); // call raise handler if present - } - - _Doraise(); // call the protected virtual - _RAISE(*this); // raise this exception - } - -protected: - virtual void __CLR_OR_THIS_CALL _Doraise() const {} // perform class-specific exception handling - - const char* _Ptr; // the message pointer -}; - -class _NODISCARD bad_exception : public exception { // base of all bad exceptions -public: - __CLR_OR_THIS_CALL bad_exception(const char* _Message = "bad exception") noexcept : exception(_Message) {} - - __CLR_OR_THIS_CALL ~bad_exception() noexcept override {} - -protected: - void __CLR_OR_THIS_CALL _Doraise() const override { // raise this exception - _RAISE(*this); - } -}; - -class _NODISCARD bad_array_new_length; - -class _NODISCARD bad_alloc : public exception { // base of all bad allocation exceptions -public: - __CLR_OR_THIS_CALL bad_alloc() noexcept - : exception("bad allocation", 1) {} // construct from message string with no memory allocation - - __CLR_OR_THIS_CALL ~bad_alloc() noexcept override {} - -private: - friend bad_array_new_length; - - __CLR_OR_THIS_CALL bad_alloc(const char* _Message) noexcept - : exception(_Message, 1) {} // construct from message string with no memory allocation - -protected: - void __CLR_OR_THIS_CALL _Doraise() const override { // perform class-specific exception handling - _RAISE(*this); - } -}; - -class _NODISCARD bad_array_new_length : public bad_alloc { -public: - bad_array_new_length() noexcept : bad_alloc("bad array new length") {} -}; - -_STDEXT_END - -_STD_BEGIN -_EXPORT_STD using terminate_handler = void(__cdecl*)(); - -_EXPORT_STD inline terminate_handler __CRTDECL set_terminate(terminate_handler) noexcept { - // register a terminate handler - return nullptr; -} - -_EXPORT_STD [[noreturn]] inline void __CRTDECL terminate() noexcept { - // handle exception termination - _CSTD abort(); -} - -_EXPORT_STD _NODISCARD inline terminate_handler __CRTDECL get_terminate() noexcept { - // get current terminate handler - return nullptr; -} - -#if _HAS_UNEXPECTED -using unexpected_handler = void(__cdecl*)(); - -inline unexpected_handler __CRTDECL set_unexpected(unexpected_handler) noexcept { - // register an unexpected handler - return nullptr; -} - -inline void __CRTDECL unexpected() {} // handle unexpected exception - -_NODISCARD inline unexpected_handler __CRTDECL get_unexpected() noexcept { - // get current unexpected handler - return nullptr; -} -#endif // _HAS_UNEXPECTED - -_EXPORT_STD using _STDEXT bad_alloc; -_EXPORT_STD using _STDEXT bad_array_new_length; -_EXPORT_STD using _STDEXT bad_exception; - -_STD_END - -#undef _STDEXT_BEGIN -#undef _STDEXT_END -#undef _STDEXT - -#pragma pop_macro("stdext") - -#endif // ^^^ !_HAS_EXCEPTIONS ^^^ - -extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCreate(_Out_ void*) noexcept; -extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrDestroy(_Inout_ void*) noexcept; -extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopy(_Out_ void*, _In_ const void*) noexcept; -extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrAssign(_Inout_ void*, _In_ const void*) noexcept; -extern "C++" _CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL __ExceptionPtrCompare( - _In_ const void*, _In_ const void*) noexcept; -extern "C++" _CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL __ExceptionPtrToBool(_In_ const void*) noexcept; -extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrSwap(_Inout_ void*, _Inout_ void*) noexcept; -extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCurrentException(void*) noexcept; -extern "C++" [[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrRethrow(_In_ const void*); -extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopyException( - _Inout_ void*, _In_ const void*, _In_ const void*) noexcept; - -_STD_BEGIN - -_EXPORT_STD class exception_ptr { -public: - exception_ptr() noexcept { - __ExceptionPtrCreate(this); - } - - exception_ptr(nullptr_t) noexcept { - __ExceptionPtrCreate(this); - } - - ~exception_ptr() noexcept { - __ExceptionPtrDestroy(this); - -#if _MSVC_STL_DESTRUCTOR_TOMBSTONES - const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; - _Data1 = _Tombstone; - _Data2 = _Tombstone; -#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES - } - - exception_ptr(const exception_ptr& _Rhs) noexcept { - __ExceptionPtrCopy(this, &_Rhs); - } - - exception_ptr& operator=(const exception_ptr& _Rhs) noexcept { - __ExceptionPtrAssign(this, &_Rhs); - return *this; - } - - exception_ptr& operator=(nullptr_t) noexcept { - exception_ptr _Ptr; - __ExceptionPtrAssign(this, &_Ptr); - return *this; - } - - explicit operator bool() const noexcept { - return __ExceptionPtrToBool(this); - } - - static exception_ptr _Copy_exception(_In_ void* _Except, _In_ const void* _Ptr) { - exception_ptr _Retval; - if (!_Ptr) { - // unsupported exceptions - return _Retval; - } - __ExceptionPtrCopyException(&_Retval, _Except, _Ptr); - return _Retval; - } - - friend void swap(exception_ptr& _Lhs, exception_ptr& _Rhs) noexcept { - __ExceptionPtrSwap(&_Lhs, &_Rhs); - } - - _NODISCARD friend bool operator==(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { - return __ExceptionPtrCompare(&_Lhs, &_Rhs); - } - - _NODISCARD friend bool operator==(const exception_ptr& _Lhs, nullptr_t) noexcept { - return !_Lhs; - } - -#if !_HAS_CXX20 - _NODISCARD friend bool operator==(nullptr_t, const exception_ptr& _Rhs) noexcept { - return !_Rhs; - } - - _NODISCARD friend bool operator!=(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { - return !(_Lhs == _Rhs); - } - - _NODISCARD friend bool operator!=(const exception_ptr& _Lhs, nullptr_t) noexcept { - return !(_Lhs == nullptr); - } - - _NODISCARD friend bool operator!=(nullptr_t, const exception_ptr& _Rhs) noexcept { - return !(nullptr == _Rhs); - } -#endif // !_HAS_CXX20 - -private: -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-private-field" -#endif // defined(__clang__) - void* _Data1{}; - void* _Data2{}; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif // defined(__clang__) -}; - -_EXPORT_STD _NODISCARD inline exception_ptr current_exception() noexcept { - exception_ptr _Retval; - __ExceptionPtrCurrentException(&_Retval); - return _Retval; -} - -_EXPORT_STD [[noreturn]] inline void rethrow_exception(_In_ exception_ptr _Ptr) { - __ExceptionPtrRethrow(&_Ptr); -} - -template -void* __GetExceptionInfo(_Ex); - -_EXPORT_STD template -_NODISCARD_SMART_PTR_ALLOC exception_ptr make_exception_ptr(_Ex _Except) noexcept { - return exception_ptr::_Copy_exception(_STD addressof(_Except), __GetExceptionInfo(_Except)); -} - -_EXPORT_STD class nested_exception { // wrap an exception_ptr -public: - nested_exception() noexcept : _Exc(_STD current_exception()) {} - - nested_exception(const nested_exception&) noexcept = default; - nested_exception& operator=(const nested_exception&) noexcept = default; - virtual ~nested_exception() noexcept {} - - [[noreturn]] void rethrow_nested() const { // throw wrapped exception_ptr - if (_Exc) { - _STD rethrow_exception(_Exc); - } else { - _STD terminate(); // per N4950 [except.nested]/4 - } - } - - _NODISCARD exception_ptr nested_ptr() const noexcept { // return wrapped exception_ptr - return _Exc; - } - -private: - exception_ptr _Exc; -}; - -template -struct _With_nested_v2 : _Uty, nested_exception { // glue user exception to nested_exception - template - explicit _With_nested_v2(_Ty&& _Arg) - : _Uty(_STD forward<_Ty>(_Arg)), nested_exception() {} // store user exception and current_exception() -}; - -_EXPORT_STD template -[[noreturn]] void throw_with_nested(_Ty&& _Arg) { - // throw user exception, glued to nested_exception if possible - using _Uty = decay_t<_Ty>; - - if constexpr (is_class_v<_Uty> && !is_base_of_v && !is_final_v<_Uty>) { - // throw user exception glued to nested_exception - _THROW(_With_nested_v2<_Uty>(_STD forward<_Ty>(_Arg))); - } else { - // throw user exception by itself - _THROW(_STD forward<_Ty>(_Arg)); - } -} - -#ifdef _CPPRTTI -_EXPORT_STD template -void rethrow_if_nested(const _Ty& _Arg) { - // detect nested_exception inheritance - constexpr bool _Can_use_dynamic_cast = - is_polymorphic_v<_Ty> && (!is_base_of_v || is_convertible_v<_Ty*, nested_exception*>); - - if constexpr (_Can_use_dynamic_cast) { - const auto _Nested = dynamic_cast(_STD addressof(_Arg)); - - if (_Nested) { - _Nested->rethrow_nested(); - } - } -} -#else // ^^^ defined(_CPPRTTI) / !defined(_CPPRTTI) vvv -_EXPORT_STD template -void rethrow_if_nested(const _Ty&) = delete; // requires /GR option -#endif // ^^^ !defined(_CPPRTTI) ^^^ - -_EXPORT_STD class _NODISCARD bad_variant_access : public exception { - // exception for visit of a valueless variant or get on a variant with index() != I -public: - bad_variant_access() noexcept = default; - - _NODISCARD const char* __CLR_OR_THIS_CALL what() const noexcept override { - return "bad variant access"; - } - -#if !_HAS_EXCEPTIONS -protected: - void _Doraise() const override { // perform class-specific exception handling - _RAISE(*this); - } -#endif // ^^^ !_HAS_EXCEPTIONS ^^^ -}; - -[[noreturn]] inline void _Throw_bad_variant_access() { - _THROW(bad_variant_access{}); -} - -_STD_END - -#pragma pop_macro("new") -_STL_RESTORE_CLANG_WARNINGS -#pragma warning(pop) -#pragma pack(pop) - -#endif // _STL_COMPILER_PREPROCESSOR -#endif // _EXCEPTION_ +// exception standard header + +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef _EXCEPTION_ +#define _EXCEPTION_ +#include +#if _STL_COMPILER_PREPROCESSOR + +#include +#include + +#pragma pack(push, _CRT_PACKING) +#pragma warning(push, _STL_WARNING_LEVEL) +#pragma warning(disable : _STL_DISABLED_WARNINGS) +_STL_DISABLE_CLANG_WARNINGS +#pragma push_macro("new") +#undef new + +_STD_BEGIN + +#if _HAS_DEPRECATED_UNCAUGHT_EXCEPTION +_EXPORT_STD extern "C++" _CXX17_DEPRECATE_UNCAUGHT_EXCEPTION _NODISCARD _CRTIMP2_PURE bool + __CLRCALL_PURE_OR_CDECL uncaught_exception() noexcept; +#endif // _HAS_DEPRECATED_UNCAUGHT_EXCEPTION +_EXPORT_STD extern "C++" _NODISCARD _CRTIMP2_PURE int __CLRCALL_PURE_OR_CDECL uncaught_exceptions() noexcept; + +_STD_END + +#if _HAS_EXCEPTIONS + +#include // TRANSITION, VSO-2048380: This is unnecessary, but many projects assume it as of 2024-04-29 +#include + +_STD_BEGIN + +_EXPORT_STD using ::terminate; + +#ifndef _M_CEE_PURE +_EXPORT_STD using ::set_terminate; +_EXPORT_STD using ::terminate_handler; + +_EXPORT_STD _NODISCARD inline terminate_handler __CRTDECL get_terminate() noexcept { + // get current terminate handler + return _get_terminate(); +} +#endif // !defined(_M_CEE_PURE) + +#if _HAS_UNEXPECTED +using ::unexpected; + +#ifndef _M_CEE_PURE +using ::set_unexpected; +using ::unexpected_handler; + +_NODISCARD inline unexpected_handler __CRTDECL get_unexpected() noexcept { + // get current unexpected handler + return _get_unexpected(); +} +#endif // !defined(_M_CEE_PURE) +#endif // _HAS_UNEXPECTED + +_STD_END + +#else // ^^^ _HAS_EXCEPTIONS / !_HAS_EXCEPTIONS vvv + +#pragma push_macro("stdext") +#undef stdext + +#define _STDEXT_BEGIN \ + _EXTERN_CXX_WORKAROUND \ + namespace stdext { + +#define _STDEXT_END \ + } \ + _END_EXTERN_CXX_WORKAROUND + +#define _STDEXT ::stdext:: + +_STDEXT_BEGIN +class _NODISCARD exception; +_STDEXT_END + +_STD_BEGIN + +_EXPORT_STD using _STDEXT exception; + +using _Prhand = void(__cdecl*)(const exception&); + +extern _CRTIMP2_PURE_IMPORT _Prhand _Raise_handler; // pointer to raise handler + +_STD_END + +_STDEXT_BEGIN +class _NODISCARD exception { // base of all library exceptions +public: + static _STD _Prhand _Set_raise_handler(_STD _Prhand _Pnew) { // register a handler for _Raise calls + const _STD _Prhand _Pold = _STD _Raise_handler; + _STD _Raise_handler = _Pnew; + return _Pold; + } + + // this constructor is necessary to compile + // successfully header new for _HAS_EXCEPTIONS==0 scenario + explicit __CLR_OR_THIS_CALL exception(const char* _Message = "unknown", int = 1) noexcept : _Ptr(_Message) {} + + __CLR_OR_THIS_CALL exception(const exception& _Right) noexcept : _Ptr(_Right._Ptr) {} + + exception& __CLR_OR_THIS_CALL operator=(const exception& _Right) noexcept { + _Ptr = _Right._Ptr; + return *this; + } + + virtual __CLR_OR_THIS_CALL ~exception() noexcept {} + + _NODISCARD virtual const char* __CLR_OR_THIS_CALL what() const noexcept { // return pointer to message string + return _Ptr ? _Ptr : "unknown exception"; + } + + [[noreturn]] void __CLR_OR_THIS_CALL _Raise() const { // raise the exception + if (_STD _Raise_handler) { + (*_STD _Raise_handler)(*this); // call raise handler if present + } + + _Doraise(); // call the protected virtual + _RAISE(*this); // raise this exception + } + +protected: + virtual void __CLR_OR_THIS_CALL _Doraise() const {} // perform class-specific exception handling + + const char* _Ptr; // the message pointer +}; + +class _NODISCARD bad_exception : public exception { // base of all bad exceptions +public: + __CLR_OR_THIS_CALL bad_exception(const char* _Message = "bad exception") noexcept : exception(_Message) {} + + __CLR_OR_THIS_CALL ~bad_exception() noexcept override {} + +protected: + void __CLR_OR_THIS_CALL _Doraise() const override { // raise this exception + _RAISE(*this); + } +}; + +class _NODISCARD bad_array_new_length; + +class _NODISCARD bad_alloc : public exception { // base of all bad allocation exceptions +public: + __CLR_OR_THIS_CALL bad_alloc() noexcept + : exception("bad allocation", 1) {} // construct from message string with no memory allocation + + __CLR_OR_THIS_CALL ~bad_alloc() noexcept override {} + +private: + friend bad_array_new_length; + + __CLR_OR_THIS_CALL bad_alloc(const char* _Message) noexcept + : exception(_Message, 1) {} // construct from message string with no memory allocation + +protected: + void __CLR_OR_THIS_CALL _Doraise() const override { // perform class-specific exception handling + _RAISE(*this); + } +}; + +class _NODISCARD bad_array_new_length : public bad_alloc { +public: + bad_array_new_length() noexcept : bad_alloc("bad array new length") {} +}; + +_STDEXT_END + +_STD_BEGIN +_EXPORT_STD using terminate_handler = void(__cdecl*)(); + +_EXPORT_STD inline terminate_handler __CRTDECL set_terminate(terminate_handler) noexcept { + // register a terminate handler + return nullptr; +} + +_EXPORT_STD [[noreturn]] inline void __CRTDECL terminate() noexcept { + // handle exception termination + _CSTD abort(); +} + +_EXPORT_STD _NODISCARD inline terminate_handler __CRTDECL get_terminate() noexcept { + // get current terminate handler + return nullptr; +} + +#if _HAS_UNEXPECTED +using unexpected_handler = void(__cdecl*)(); + +inline unexpected_handler __CRTDECL set_unexpected(unexpected_handler) noexcept { + // register an unexpected handler + return nullptr; +} + +inline void __CRTDECL unexpected() {} // handle unexpected exception + +_NODISCARD inline unexpected_handler __CRTDECL get_unexpected() noexcept { + // get current unexpected handler + return nullptr; +} +#endif // _HAS_UNEXPECTED + +_EXPORT_STD using _STDEXT bad_alloc; +_EXPORT_STD using _STDEXT bad_array_new_length; +_EXPORT_STD using _STDEXT bad_exception; + +_STD_END + +#undef _STDEXT_BEGIN +#undef _STDEXT_END +#undef _STDEXT + +#pragma pop_macro("stdext") + +#endif // ^^^ !_HAS_EXCEPTIONS ^^^ + +extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCreate(_Out_ void*) noexcept; +extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrDestroy(_Inout_ void*) noexcept; +extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopy(_Out_ void*, _In_ const void*) noexcept; +extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrAssign(_Inout_ void*, _In_ const void*) noexcept; +extern "C++" _CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL __ExceptionPtrCompare( + _In_ const void*, _In_ const void*) noexcept; +extern "C++" _CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL __ExceptionPtrToBool(_In_ const void*) noexcept; +extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrSwap(_Inout_ void*, _Inout_ void*) noexcept; +extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCurrentException(void*) noexcept; +extern "C++" [[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrRethrow(_In_ const void*); +extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopyException( + _Inout_ void*, _In_ const void*, _In_ const void*) noexcept; + +_STD_BEGIN + +_EXPORT_STD class exception_ptr { +public: + exception_ptr() noexcept {} + + exception_ptr(nullptr_t) noexcept {} + + ~exception_ptr() noexcept { + __ExceptionPtrDestroy(this); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Data1 = _Tombstone; + _Data2 = _Tombstone; +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + } + + exception_ptr(const exception_ptr& _Rhs) noexcept { + __ExceptionPtrCopy(this, &_Rhs); + } + + exception_ptr& operator=(const exception_ptr& _Rhs) noexcept { + __ExceptionPtrAssign(this, &_Rhs); + return *this; + } + + exception_ptr& operator=(nullptr_t) noexcept { + exception_ptr _Ptr; + swap(*this, _Ptr); + return *this; + } + + explicit operator bool() const noexcept { + return _Data1 != nullptr; + } + + static exception_ptr _Copy_exception(_In_ void* _Except, _In_ const void* _Ptr) { + exception_ptr _Retval; + if (!_Ptr) { + // unsupported exceptions + return _Retval; + } + __ExceptionPtrCopyException(&_Retval, _Except, _Ptr); + return _Retval; + } + + friend void swap(exception_ptr& _Lhs, exception_ptr& _Rhs) noexcept { + void* const _LhsData1 = _Lhs._Data1; + void* const _LhsData2 = _Lhs._Data2; + _Lhs._Data1 = _Rhs._Data1; + _Lhs._Data2 = _Rhs._Data2; + _Rhs._Data1 = _LhsData1; + _Rhs._Data2 = _LhsData2; + } + + _NODISCARD friend bool operator==(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { + return _Lhs._Data1 == _Rhs._Data1; + } + + _NODISCARD friend bool operator==(const exception_ptr& _Lhs, nullptr_t) noexcept { + return !_Lhs; + } + +#if !_HAS_CXX20 + _NODISCARD friend bool operator==(nullptr_t, const exception_ptr& _Rhs) noexcept { + return !_Rhs; + } + + _NODISCARD friend bool operator!=(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept { + return !(_Lhs == _Rhs); + } + + _NODISCARD friend bool operator!=(const exception_ptr& _Lhs, nullptr_t) noexcept { + return !(_Lhs == nullptr); + } + + _NODISCARD friend bool operator!=(nullptr_t, const exception_ptr& _Rhs) noexcept { + return !(nullptr == _Rhs); + } +#endif // !_HAS_CXX20 + +private: +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif // defined(__clang__) + void* _Data1{}; + void* _Data2{}; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // defined(__clang__) +}; + +_EXPORT_STD _NODISCARD inline exception_ptr current_exception() noexcept { + exception_ptr _Retval; + __ExceptionPtrCurrentException(&_Retval); + return _Retval; +} + +_EXPORT_STD [[noreturn]] inline void rethrow_exception(_In_ exception_ptr _Ptr) { + __ExceptionPtrRethrow(&_Ptr); +} + +template +void* __GetExceptionInfo(_Ex); + +_EXPORT_STD template +_NODISCARD_SMART_PTR_ALLOC exception_ptr make_exception_ptr(_Ex _Except) noexcept { + return exception_ptr::_Copy_exception(_STD addressof(_Except), __GetExceptionInfo(_Except)); +} + +_EXPORT_STD class nested_exception { // wrap an exception_ptr +public: + nested_exception() noexcept : _Exc(_STD current_exception()) {} + + nested_exception(const nested_exception&) noexcept = default; + nested_exception& operator=(const nested_exception&) noexcept = default; + virtual ~nested_exception() noexcept {} + + [[noreturn]] void rethrow_nested() const { // throw wrapped exception_ptr + if (_Exc) { + _STD rethrow_exception(_Exc); + } else { + _STD terminate(); // per N4950 [except.nested]/4 + } + } + + _NODISCARD exception_ptr nested_ptr() const noexcept { // return wrapped exception_ptr + return _Exc; + } + +private: + exception_ptr _Exc; +}; + +template +struct _With_nested_v2 : _Uty, nested_exception { // glue user exception to nested_exception + template + explicit _With_nested_v2(_Ty&& _Arg) + : _Uty(_STD forward<_Ty>(_Arg)), nested_exception() {} // store user exception and current_exception() +}; + +_EXPORT_STD template +[[noreturn]] void throw_with_nested(_Ty&& _Arg) { + // throw user exception, glued to nested_exception if possible + using _Uty = decay_t<_Ty>; + + if constexpr (is_class_v<_Uty> && !is_base_of_v && !is_final_v<_Uty>) { + // throw user exception glued to nested_exception + _THROW(_With_nested_v2<_Uty>(_STD forward<_Ty>(_Arg))); + } else { + // throw user exception by itself + _THROW(_STD forward<_Ty>(_Arg)); + } +} + +#ifdef _CPPRTTI +_EXPORT_STD template +void rethrow_if_nested(const _Ty& _Arg) { + // detect nested_exception inheritance + constexpr bool _Can_use_dynamic_cast = + is_polymorphic_v<_Ty> && (!is_base_of_v || is_convertible_v<_Ty*, nested_exception*>); + + if constexpr (_Can_use_dynamic_cast) { + const auto _Nested = dynamic_cast(_STD addressof(_Arg)); + + if (_Nested) { + _Nested->rethrow_nested(); + } + } +} +#else // ^^^ defined(_CPPRTTI) / !defined(_CPPRTTI) vvv +_EXPORT_STD template +void rethrow_if_nested(const _Ty&) = delete; // requires /GR option +#endif // ^^^ !defined(_CPPRTTI) ^^^ + +_EXPORT_STD class _NODISCARD bad_variant_access : public exception { + // exception for visit of a valueless variant or get on a variant with index() != I +public: + bad_variant_access() noexcept = default; + + _NODISCARD const char* __CLR_OR_THIS_CALL what() const noexcept override { + return "bad variant access"; + } + +#if !_HAS_EXCEPTIONS +protected: + void _Doraise() const override { // perform class-specific exception handling + _RAISE(*this); + } +#endif // ^^^ !_HAS_EXCEPTIONS ^^^ +}; + +[[noreturn]] inline void _Throw_bad_variant_access() { + _THROW(bad_variant_access{}); +} + +_STD_END + +#pragma pop_macro("new") +_STL_RESTORE_CLANG_WARNINGS +#pragma warning(pop) +#pragma pack(pop) + +#endif // _STL_COMPILER_PREPROCESSOR +#endif // _EXCEPTION_