exception.hpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. #ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED
  2. #define BOOST_LEAF_EXCEPTION_HPP_INCLUDED
  3. // Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #include <boost/leaf/config.hpp>
  7. #include <boost/leaf/error.hpp>
  8. #include <exception>
  9. #include <typeinfo>
  10. #ifdef BOOST_LEAF_NO_EXCEPTIONS
  11. namespace boost
  12. {
  13. [[noreturn]] void throw_exception( std::exception const & ); // user defined
  14. }
  15. namespace boost { namespace leaf {
  16. namespace detail
  17. {
  18. template <class T>
  19. [[noreturn]] void throw_exception_impl( T && e )
  20. {
  21. ::boost::throw_exception(std::move(e));
  22. }
  23. }
  24. } }
  25. #else
  26. namespace boost { namespace leaf {
  27. namespace detail
  28. {
  29. template <class T>
  30. [[noreturn]] void throw_exception_impl( T && e )
  31. {
  32. throw std::move(e);
  33. }
  34. }
  35. } }
  36. #endif
  37. ////////////////////////////////////////
  38. #define BOOST_LEAF_THROW_EXCEPTION ::boost::leaf::detail::throw_with_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::detail::make_exception
  39. namespace boost { namespace leaf {
  40. namespace detail
  41. {
  42. struct throw_with_loc
  43. {
  44. char const * const file;
  45. int const line;
  46. char const * const fn;
  47. template <class Ex>
  48. [[noreturn]] friend void operator+( throw_with_loc loc, Ex && ex )
  49. {
  50. ex.load_source_location_(loc.file, loc.line, loc.fn);
  51. ::boost::leaf::detail::throw_exception_impl(std::move(ex));
  52. }
  53. };
  54. }
  55. ////////////////////////////////////////
  56. namespace detail
  57. {
  58. inline void enforce_std_exception( std::exception const & ) noexcept { }
  59. template <class Ex>
  60. class BOOST_LEAF_SYMBOL_VISIBLE exception:
  61. public Ex,
  62. public exception_base,
  63. public error_id
  64. {
  65. mutable bool clear_current_error_;
  66. bool is_current_exception() const noexcept
  67. {
  68. return tls::read_uint<detail::tls_tag_id_factory_current_id>() == unsigned(error_id::value());
  69. }
  70. error_id get_error_id() const noexcept final override
  71. {
  72. clear_current_error_ = false;
  73. return *this;
  74. }
  75. #if BOOST_LEAF_CFG_DIAGNOSTICS && !defined(BOOST_LEAF_NO_EXCEPTIONS)
  76. void print_type_name(std::ostream & os) const final override
  77. {
  78. detail::demangle_and_print(os, typeid(Ex).name());
  79. }
  80. #endif
  81. public:
  82. exception( exception const & other ):
  83. Ex(other),
  84. exception_base(other),
  85. error_id(other),
  86. clear_current_error_(other.clear_current_error_)
  87. {
  88. other.clear_current_error_ = false;
  89. }
  90. exception( exception && other ) noexcept:
  91. Ex(std::move(other)),
  92. exception_base(std::move(other)),
  93. error_id(std::move(other)),
  94. clear_current_error_(std::move(other.clear_current_error_))
  95. {
  96. other.clear_current_error_ = false;
  97. }
  98. exception( error_id id, Ex const & ex ) noexcept:
  99. Ex(ex),
  100. error_id(id),
  101. clear_current_error_(true)
  102. {
  103. enforce_std_exception(*this);
  104. }
  105. exception( error_id id, Ex && ex ) noexcept:
  106. Ex(std::move(ex)),
  107. error_id(id),
  108. clear_current_error_(true)
  109. {
  110. enforce_std_exception(*this);
  111. }
  112. explicit exception( error_id id ) noexcept:
  113. error_id(id),
  114. clear_current_error_(true)
  115. {
  116. enforce_std_exception(*this);
  117. }
  118. ~exception() noexcept
  119. {
  120. if( clear_current_error_ && is_current_exception() )
  121. tls::write_uint<detail::tls_tag_id_factory_current_id>(0);
  122. }
  123. };
  124. template <class... T>
  125. struct at_least_one_derives_from_std_exception;
  126. template <>
  127. struct at_least_one_derives_from_std_exception<>: std::false_type { };
  128. template <class T, class... Rest>
  129. struct at_least_one_derives_from_std_exception<T, Rest...>
  130. {
  131. constexpr static const bool value = std::is_base_of<std::exception,typename std::remove_reference<T>::type>::value || at_least_one_derives_from_std_exception<Rest...>::value;
  132. };
  133. template <class Ex, class... E>
  134. inline
  135. typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
  136. make_exception( error_id err, Ex && ex, E && ... e ) noexcept
  137. {
  138. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  139. return exception<typename std::remove_reference<Ex>::type>( err.load(std::forward<E>(e)...), std::forward<Ex>(ex) );
  140. }
  141. template <class E1, class... E>
  142. inline
  143. typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
  144. make_exception( error_id err, E1 && car, E && ... cdr ) noexcept
  145. {
  146. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  147. return exception<std::exception>( err.load(std::forward<E1>(car), std::forward<E>(cdr)...) );
  148. }
  149. inline exception<std::exception> make_exception( error_id err ) noexcept
  150. {
  151. return exception<std::exception>(err);
  152. }
  153. template <class Ex, class... E>
  154. inline
  155. typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
  156. make_exception( Ex && ex, E && ... e ) noexcept
  157. {
  158. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  159. return exception<typename std::remove_reference<Ex>::type>( new_error().load(std::forward<E>(e)...), std::forward<Ex>(ex) );
  160. }
  161. template <class E1, class... E>
  162. inline
  163. typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
  164. make_exception( E1 && car, E && ... cdr ) noexcept
  165. {
  166. static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
  167. return exception<std::exception>( new_error().load(std::forward<E1>(car), std::forward<E>(cdr)...) );
  168. }
  169. inline exception<std::exception> make_exception() noexcept
  170. {
  171. return exception<std::exception>(leaf::new_error());
  172. }
  173. }
  174. template <class... E>
  175. [[noreturn]] void throw_exception( E && ... e )
  176. {
  177. // Warning: setting a breakpoint here will not intercept exceptions thrown
  178. // via BOOST_LEAF_THROW_EXCEPTION or originating in the few other throw
  179. // points elsewhere in LEAF. To intercept all of those exceptions as well,
  180. // set a breakpoint inside boost::leaf::detail::throw_exception_impl.
  181. detail::throw_exception_impl(detail::make_exception(std::forward<E>(e)...));
  182. }
  183. ////////////////////////////////////////
  184. #ifndef BOOST_LEAF_NO_EXCEPTIONS
  185. template <class T>
  186. class BOOST_LEAF_SYMBOL_VISIBLE result;
  187. namespace detail
  188. {
  189. inline error_id catch_exceptions_helper( std::exception const &, leaf_detail_mp11::mp_list<> )
  190. {
  191. return leaf::new_error(std::current_exception());
  192. }
  193. template <class Ex1, class... Ex>
  194. inline error_id catch_exceptions_helper( std::exception const & ex, leaf_detail_mp11::mp_list<Ex1,Ex...> )
  195. {
  196. if( Ex1 const * p = dynamic_cast<Ex1 const *>(&ex) )
  197. return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ }).load(*p);
  198. else
  199. return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ });
  200. }
  201. template <class T>
  202. struct deduce_exception_to_result_return_type_impl
  203. {
  204. using type = result<T>;
  205. };
  206. template <class T>
  207. struct deduce_exception_to_result_return_type_impl<result<T>>
  208. {
  209. using type = result<T>;
  210. };
  211. template <class T>
  212. using deduce_exception_to_result_return_type = typename deduce_exception_to_result_return_type_impl<T>::type;
  213. }
  214. template <class... Ex, class F>
  215. inline
  216. detail::deduce_exception_to_result_return_type<detail::fn_return_type<F>>
  217. exception_to_result( F && f ) noexcept
  218. {
  219. try
  220. {
  221. return std::forward<F>(f)();
  222. }
  223. catch( std::exception const & ex )
  224. {
  225. return detail::catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>());
  226. }
  227. catch(...)
  228. {
  229. return leaf::new_error(std::current_exception());
  230. }
  231. }
  232. #endif
  233. } }
  234. #endif // BOOST_LEAF_EXCEPTION_HPP_INCLUDED