#ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED #define BOOST_LEAF_EXCEPTION_HPP_INCLUDED // Copyright 2018-2026 Emil Dotchevski and Reverge Studios, Inc. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #include #ifndef BOOST_LEAF_NO_EXCEPTIONS # include #endif namespace boost { namespace leaf { namespace serialization { template void output(Encoder & e, std::exception const & x) { char const dynamic_type[] = "dynamic_type"; char const what[] = "what"; #ifdef BOOST_LEAF_NO_EXCEPTIONS output_at(e, "<>", dynamic_type); #else output_at(e, detail::demangler(typeid(x).name()).get(), dynamic_type); #endif if( char const * wh = x.what() ) output_at(e, wh, what); else output_at(e, "<>", what); } template void output(Encoder & e, std::exception_ptr const & x) { if( x ) { #ifndef BOOST_LEAF_NO_EXCEPTIONS try { std::rethrow_exception(x); } catch( std::exception const & ex ) { output(e, ex); return; } catch( ... ) { } #endif output_at(e, "<>", "dynamic_type"); } else output_at(e, "<>", "dynamic_type"); output_at(e, "N/A", "what"); } } } } //////////////////////////////////////// #define BOOST_LEAF_THROW_EXCEPTION ::boost::leaf::detail::throw_with_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::detail::make_exception namespace boost { namespace leaf { namespace detail { struct throw_with_loc { char const * const file; int const line; char const * const fn; template [[noreturn]] friend void operator+( throw_with_loc loc, Ex && ex ) { ex.load_source_location_(loc.file, loc.line, loc.fn); ::boost::leaf::throw_exception_(std::move(ex)); } }; } //////////////////////////////////////// namespace detail { inline void enforce_std_exception( std::exception const & ) noexcept { } template class exception final: public Ex, public exception_base, public error_id { mutable bool clear_current_error_; bool is_current_exception() const noexcept { return tls::read_current_error_id() == unsigned(error_id::value()); } error_id get_error_id() const noexcept override { clear_current_error_ = false; return *this; } detail::type_name get_type_name() const override { return detail::get_type_name(); } public: exception( exception const & other ): Ex(other), exception_base(other), error_id(other), clear_current_error_(other.clear_current_error_) { other.clear_current_error_ = false; } exception( exception && other ) noexcept: Ex(std::move(other)), exception_base(std::move(other)), error_id(std::move(other)), clear_current_error_(std::move(other.clear_current_error_)) { other.clear_current_error_ = false; } exception( error_id id, Ex const & ex ) noexcept: Ex(ex), error_id(id), clear_current_error_(true) { enforce_std_exception(*this); } exception( error_id id, Ex && ex ) noexcept: Ex(std::move(ex)), error_id(id), clear_current_error_(true) { enforce_std_exception(*this); } explicit exception( error_id id ) noexcept: error_id(id), clear_current_error_(true) { enforce_std_exception(*this); } ~exception() noexcept { if( clear_current_error_ && is_current_exception() ) tls::write_current_error_id(0); } }; // template exception template struct at_least_one_derives_from_std_exception; template <> struct at_least_one_derives_from_std_exception<>: std::false_type { }; template struct at_least_one_derives_from_std_exception { constexpr static const bool value = std::is_base_of::type>::value || at_least_one_derives_from_std_exception::value; }; template inline typename std::enable_if::type>::value, exception::type>>::type make_exception( error_id err, Ex && ex, E && ... e ) noexcept(!BOOST_LEAF_CFG_CAPTURE) { static_assert(!at_least_one_derives_from_std_exception::value, "Error objects passed to leaf::exception may not derive from std::exception"); return exception::type>( err.load(std::forward(e)...), std::forward(ex) ); } template inline typename std::enable_if::type>::value, exception>::type make_exception( error_id err, E1 && car, E && ... cdr ) noexcept(!BOOST_LEAF_CFG_CAPTURE) { static_assert(!at_least_one_derives_from_std_exception::value, "Error objects passed to leaf::exception may not derive from std::exception"); return exception( err.load(std::forward(car), std::forward(cdr)...) ); } inline exception make_exception( error_id err ) noexcept { return exception(err); } template inline typename std::enable_if::type>::value, exception::type>>::type make_exception( Ex && ex, E && ... e ) noexcept(!BOOST_LEAF_CFG_CAPTURE) { static_assert(!at_least_one_derives_from_std_exception::value, "Error objects passed to leaf::exception may not derive from std::exception"); return exception::type>( new_error().load(std::forward(e)...), std::forward(ex) ); } template inline typename std::enable_if::type>::value, exception>::type make_exception( E1 && car, E && ... cdr ) noexcept(!BOOST_LEAF_CFG_CAPTURE) { static_assert(!at_least_one_derives_from_std_exception::value, "Error objects passed to leaf::exception may not derive from std::exception"); return exception( new_error().load(std::forward(car), std::forward(cdr)...) ); } inline exception make_exception() noexcept { return exception(leaf::new_error()); } } // namespace detail template [[noreturn]] void throw_exception( E && ... e ) { // Warning: setting a breakpoint here will not intercept exceptions thrown // via BOOST_LEAF_THROW_EXCEPTION or originating in the few other throw // points elsewhere in LEAF. To intercept all of those exceptions as well, // set a breakpoint inside boost::leaf::throw_exception_. throw_exception_(detail::make_exception(std::forward(e)...)); } //////////////////////////////////////// #ifndef BOOST_LEAF_NO_EXCEPTIONS namespace detail { inline error_id catch_exceptions_helper( std::exception const &, leaf_detail_mp11::mp_list<> ) { return leaf::new_error(std::current_exception()); } template inline error_id catch_exceptions_helper( std::exception const & ex, leaf_detail_mp11::mp_list ) { if( Ex1 const * p = dynamic_cast(&ex) ) return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list{ }).load(*p); else return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list{ }); } template struct deduce_exception_to_result_return_type_impl { using type = result; }; template struct deduce_exception_to_result_return_type_impl> { using type = result; }; template using deduce_exception_to_result_return_type = typename deduce_exception_to_result_return_type_impl::type; } // namespace detail template inline detail::deduce_exception_to_result_return_type> exception_to_result( F && f ) noexcept(!BOOST_LEAF_CFG_CAPTURE) { try { return std::forward(f)(); } catch( std::exception const & ex ) { return detail::catch_exceptions_helper(ex, leaf_detail_mp11::mp_list()); } catch(...) { return leaf::new_error(std::current_exception()); } } #endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS } } // namespace boost::leaf #endif // #ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED