зеркало из https://github.com/microsoft/STL.git
423 строки
13 KiB
C++
423 строки
13 KiB
C++
// exception standard header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef _EXCEPTION_
|
|
#define _EXCEPTION_
|
|
#include <yvals.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
|
|
#include <cstdlib>
|
|
#include <type_traits>
|
|
|
|
#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 <malloc.h> // TRANSITION, VSO-2048380: This is unnecessary, but many projects assume it as of 2024-04-29
|
|
#include <vcruntime_exception.h>
|
|
|
|
_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 <class _Ex>
|
|
void* __GetExceptionInfo(_Ex);
|
|
|
|
_EXPORT_STD template <class _Ex>
|
|
_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 <class _Uty>
|
|
struct _With_nested_v2 : _Uty, nested_exception { // glue user exception to nested_exception
|
|
template <class _Ty>
|
|
explicit _With_nested_v2(_Ty&& _Arg)
|
|
: _Uty(_STD forward<_Ty>(_Arg)), nested_exception() {} // store user exception and current_exception()
|
|
};
|
|
|
|
_EXPORT_STD template <class _Ty>
|
|
[[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<nested_exception, _Uty> && !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 <class _Ty>
|
|
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<nested_exception, _Ty> || is_convertible_v<_Ty*, nested_exception*>);
|
|
|
|
if constexpr (_Can_use_dynamic_cast) {
|
|
const auto _Nested = dynamic_cast<const nested_exception*>(_STD addressof(_Arg));
|
|
|
|
if (_Nested) {
|
|
_Nested->rethrow_nested();
|
|
}
|
|
}
|
|
}
|
|
#else // ^^^ defined(_CPPRTTI) / !defined(_CPPRTTI) vvv
|
|
_EXPORT_STD template <class _Ty>
|
|
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<I> 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_
|