Add exception wrapping utilities, will help issues like #60

This commit is contained in:
Jeremy 2023-11-15 21:24:26 -05:00
parent 61d536bc02
commit ab7e71f1b2
No known key found for this signature in database
GPG Key ID: BE03111EB7ED6E2E
2 changed files with 62 additions and 1 deletions

View File

@ -244,7 +244,7 @@ namespace cpptrace {
protected: protected:
explicit exception_with_message( explicit exception_with_message(
std::string&& message_arg, std::string&& message_arg,
std::uint32_t skip std::size_t skip
) noexcept : exception(skip + 1), message(std::move(message_arg)) {} ) noexcept : exception(skip + 1), message(std::move(message_arg)) {}
explicit exception_with_message( explicit exception_with_message(
@ -313,6 +313,21 @@ namespace cpptrace {
explicit underflow_error(std::string&& message_arg) noexcept explicit underflow_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {} : exception_with_message(std::move(message_arg), 1) {}
}; };
class CPPTRACE_EXPORT nested_exception : public exception {
std::exception_ptr ptr;
mutable std::string what_value;
public:
explicit nested_exception(std::exception_ptr exception_ptr) noexcept
: exception(1), ptr(exception_ptr) {}
explicit nested_exception(std::exception_ptr exception_ptr, std::size_t skip) noexcept
: exception(skip + 1), ptr(exception_ptr) {}
const char* get_raw_what() const noexcept override;
std::exception_ptr nested_ptr() const noexcept;
};
CPPTRACE_EXPORT [[noreturn]] void rethrow_and_wrap_if_needed(std::size_t skip = 0);
} }
#if defined(CPPTRACE_STD_FORMAT) && defined(__cpp_lib_format) #if defined(CPPTRACE_STD_FORMAT) && defined(__cpp_lib_format)
@ -331,4 +346,21 @@ namespace cpptrace {
}; };
#endif #endif
// Exception wrapper utilities
#define CPPTRACE_WRAP_BLOCK(statements) do { \
try { \
statements \
} catch(...) { \
::cpptrace::rethrow_and_wrap_if_needed(); \
} \
} while(0);
#define CPPTRACE_WRAP(expression) [&] () -> decltype((expression)) { \
try { \
return expression; \
} catch(...) { \
::cpptrace::rethrow_and_wrap_if_needed(1); \
} \
} ()
#endif #endif

View File

@ -362,6 +362,7 @@ namespace cpptrace {
} }
[[noreturn]] void terminate_handler() { [[noreturn]] void terminate_handler() {
// TODO: Support std::nested_exception?
try { try {
auto ptr = std::current_exception(); auto ptr = std::current_exception();
if(ptr == nullptr) { if(ptr == nullptr) {
@ -486,4 +487,32 @@ namespace cpptrace {
const char* exception_with_message::get_raw_what() const noexcept { const char* exception_with_message::get_raw_what() const noexcept {
return message.c_str(); return message.c_str();
} }
const char* nested_exception::get_raw_what() const noexcept {
if(what_value.empty()) {
try {
std::rethrow_exception(ptr);
} catch(std::exception& e) {
// what_value = std::string("cpptrace::nested_exception: ") + e.what();
what_value = e.what();
} catch(...) {
what_value = "<cpptrace::nested_exception holding instance of " + detail::exception_type_name() + ">";
}
}
return what_value.c_str();
}
std::exception_ptr nested_exception::nested_ptr() const noexcept {
return ptr;
}
void rethrow_and_wrap_if_needed(std::size_t skip) {
try {
std::rethrow_exception(std::current_exception());
} catch(cpptrace::exception&) {
throw; // already a cpptrace::exception
} catch(...) {
throw nested_exception(std::current_exception(), skip + 1);
}
}
} }