// 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 _STDEXT_BEGIN class 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 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 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 bad_array_new_length; class 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 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 #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); } 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 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_