diff --git a/include/cpptrace/cpptrace.hpp b/include/cpptrace/cpptrace.hpp index 6b3757f..86013f2 100644 --- a/include/cpptrace/cpptrace.hpp +++ b/include/cpptrace/cpptrace.hpp @@ -244,7 +244,7 @@ namespace cpptrace { protected: explicit exception_with_message( std::string&& message_arg, - std::uint32_t skip + std::size_t skip ) noexcept : exception(skip + 1), message(std::move(message_arg)) {} explicit exception_with_message( @@ -313,6 +313,21 @@ namespace cpptrace { explicit underflow_error(std::string&& message_arg) noexcept : 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) @@ -331,4 +346,21 @@ namespace cpptrace { }; #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 diff --git a/src/cpptrace.cpp b/src/cpptrace.cpp index f3cb860..96ac7a3 100644 --- a/src/cpptrace.cpp +++ b/src/cpptrace.cpp @@ -362,6 +362,7 @@ namespace cpptrace { } [[noreturn]] void terminate_handler() { + // TODO: Support std::nested_exception? try { auto ptr = std::current_exception(); if(ptr == nullptr) { @@ -486,4 +487,32 @@ namespace cpptrace { const char* exception_with_message::get_raw_what() const noexcept { 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 = ""; + } + } + 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); + } + } }