#ifndef CPPTRACE_FROM_CURRENT_HPP #define CPPTRACE_FROM_CURRENT_HPP #include #include #include #ifdef _MSC_VER #include #endif #include #include CPPTRACE_BEGIN_NAMESPACE CPPTRACE_EXPORT const raw_trace& raw_trace_from_current_exception(); CPPTRACE_EXPORT const stacktrace& from_current_exception(); CPPTRACE_EXPORT const raw_trace& raw_trace_from_current_exception_rethrow(); CPPTRACE_EXPORT const stacktrace& from_current_exception_rethrow(); CPPTRACE_EXPORT bool current_exception_was_rethrown(); CPPTRACE_NORETURN CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE void rethrow(); CPPTRACE_NORETURN CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE void rethrow(std::exception_ptr exception); CPPTRACE_EXPORT void clear_current_exception_traces(); namespace detail { template struct argument; template struct argument { using type = Arg; }; template struct argument { using type = void; }; #ifdef _MSC_VER CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE int maybe_collect_trace(_EXCEPTION_POINTERS* exception_ptrs, int filter_result); CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE void maybe_collect_trace(_EXCEPTION_POINTERS* exception_ptrs, const std::type_info& type_info); template CPPTRACE_FORCE_NO_INLINE inline int exception_filter(_EXCEPTION_POINTERS* exception_ptrs) { maybe_collect_trace(exception_ptrs, typeid(E)); return EXCEPTION_CONTINUE_SEARCH; } class dont_return_from_try_catch_macros { public: explicit dont_return_from_try_catch_macros() = default; }; #else CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE void maybe_collect_trace(const std::type_info*, const std::type_info*, void**, unsigned); template class unwind_interceptor { public: static int init; CPPTRACE_FORCE_NO_INLINE static bool can_catch( const std::type_info* /* this */, const std::type_info* throw_type, void** throw_obj, unsigned outer ) { maybe_collect_trace(&typeid(T), throw_type, throw_obj, outer); return false; } }; CPPTRACE_EXPORT void do_prepare_unwind_interceptor( const std::type_info&, bool(*)(const std::type_info*, const std::type_info*, void**, unsigned) ); template inline int prepare_unwind_interceptor() { do_prepare_unwind_interceptor(typeid(unwind_interceptor), unwind_interceptor::can_catch); return 1; } template int unwind_interceptor::init = prepare_unwind_interceptor(); template using unwind_interceptor_for = unwind_interceptor::type>; inline void nop(int) {} #endif } namespace detail { template Arg get_callable_argument_helper(R(*) (Arg)); template Arg get_callable_argument_helper(R(F::*) (Arg)); template Arg get_callable_argument_helper(R(F::*) (Arg) const); template void get_callable_argument_helper(R(*) ()); template void get_callable_argument_helper(R(F::*) ()); template void get_callable_argument_helper(R(F::*) () const); template decltype(get_callable_argument_helper(&F::operator())) get_callable_argument_wrapper(F); template using get_callable_argument = decltype(get_callable_argument_wrapper(std::declval())); template::value, int>::type = 0> void do_try_catch(F&& f, Catch&& catcher) { CPPTRACE_TRY { std::forward(f)(); } CPPTRACE_CATCH(E e) { std::forward(catcher)(std::forward(e)); } } template::value, int>::type = 0> void do_try_catch(F&& f, Catch&& catcher) { CPPTRACE_TRY { std::forward(f)(); } CPPTRACE_CATCH(...) { std::forward(catcher)(); } } template void try_catch_impl(F&& f) { std::forward(f)(); } // TODO: This could be made more efficient to reduce the number of interceptor levels that do typeid checks // and possible traces template void try_catch_impl(F&& f, Catch&& catcher, Catches&&... catches) { // match the first catch at the inner-most level... no real way to reverse a pack or extract from the end so // we have to wrap with a lambda auto wrapped = [&] () { using E = get_callable_argument; do_try_catch(std::forward(f), std::forward(catcher)); }; try_catch_impl(std::move(wrapped), std::forward(catches)...); } } template void try_catch(F&& f, Catches&&... catches) { return detail::try_catch_impl(std::forward(f), std::forward(catches)...); } CPPTRACE_END_NAMESPACE #endif