From af98afb3d140c076e27fb8b1adaa1d25624982fd Mon Sep 17 00:00:00 2001
From: dmenendez-gruposantander
<50944968+dmenendez-gruposantander@users.noreply.github.com>
Date: Wed, 29 Jan 2020 22:41:48 +0100
Subject: [PATCH] Attempt to solve issue #10 (#24)
* Attempt to solve issue #10
In boost::current_exception(), after all supported types of exception have
been checked for, a boost::unknown_exception is stored in the
boost::exception_ptr as a last resort to signal that an exception was indeed
stored, but that the actual type and value of the exception was lost.
Now, in case C++11 std::current_exception() is supported, the
std::exception_ptr result of calling std::current_exception() is what
gets stored inside the boost::exception_ptr. Later, inside
boost::rethrow_exception, the std::exception_ptr is retrieved from
the boost::exception_ptr and whatever exception it stores is thrown via
std::rethrow_exception().
The main benefit is than now any exception thrown via plain 'throw'
can be trasnported via boost::exception_ptr. Before this change it was
required that the throw site either used boost::enable_current_exception()
or boost::throw_exception() or threw an exception type inheriting from
boost::exception, which was impossible for third party software
that does not use Boost.Exception.
The detection of std::current_exception() is currently done via config macro
BOOST_NO_CXX11_NOEXCEPT, assuming that if 'noexcept' is supported then
std::exception_ptr is also supported. A better solution would require a new
dedicated macro in Boost.Config.
* Detect support for std::current_exception() via config macro BOOST_NO_CXX11_HDR_EXCEPTION
The temporary solution via BOOST_NO_CXX11_NOEXCEPT was an ugly hack
that is no longer necessary now that Boost.Config has
BOOST_NO_CXX11_HDR_EXCEPTION (pending merge to develop).
* Attempt to solve issue #10
In boost::current_exception(), after all supported types of exception have
been checked for, a boost::unknown_exception is stored in the
boost::exception_ptr as a last resort to signal that an exception was indeed
stored, but that the actual type and value of the exception was lost.
Now, in case C++11 std::current_exception() is supported, the
std::exception_ptr result of calling std::current_exception() is what
gets stored inside the boost::exception_ptr. Later, inside
boost::rethrow_exception, the std::exception_ptr is retrieved from
the boost::exception_ptr and whatever exception it stores is thrown via
std::rethrow_exception().
The main benefit is than now any exception thrown via plain 'throw'
can be trasnported via boost::exception_ptr. Before this change it was
required that the throw site either used boost::enable_current_exception()
or boost::throw_exception() or threw an exception type inheriting from
boost::exception, which was impossible for third party software
that does not use Boost.Exception.
The detection of std::current_exception() is currently done via config macro
BOOST_NO_CXX11_NOEXCEPT, assuming that if 'noexcept' is supported then
std::exception_ptr is also supported. A better solution would require a new
dedicated macro in Boost.Config.
* Detect support for std::current_exception() via config macro BOOST_NO_CXX11_HDR_EXCEPTION
The temporary solution via BOOST_NO_CXX11_NOEXCEPT was an ugly hack
that is no longer necessary now that Boost.Config has
BOOST_NO_CXX11_HDR_EXCEPTION (pending merge to develop).
* Document detection of C++11 std::current_exception through BOOST_NO_CXX11_HDR_EXCEPTION
* Added dist: trusty for Travis config, as recommended by pdimov in issue #10
* Stupid gcc 4.7 and 4.8 are confused initializing a reference with braces, using equal sign hoping it works (tested similar code on godbolt).
---
doc/current_exception.html | 2 +-
.../boost/exception/detail/exception_ptr.hpp | 31 +++++
test/unknown_exception_test.cpp | 129 ++++++++++++++++++
3 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/doc/current_exception.html b/doc/current_exception.html
index d8b369b..b213da9 100644
--- a/doc/current_exception.html
+++ b/doc/current_exception.html
@@ -38,7 +38,7 @@ boost
Nothing.
Notes:
- It is unspecified whether the return values of two successive calls to current_exception refer to the same exception object.
-- Correct implementation of current_exception may require compiler support, unless enable_current_exception was used at the time the currently handled exception object was passed to throw. Whenever current_exception fails to properly copy the current exception object, it returns an exception_ptr to an object of type that is as close as possible to the original exception type, using unknown_exception as a final fallback. All such types derive from boost::exception, and:
- if the original exception object derives from boost::exception, then the boost::exception sub-object of the object referred to by the returned exception_ptr is initialized by the boost::exception copy constructor;
+- Correct implementation of current_exception may require compiler support (e.g. C++11 std::current_exception() is used when available, as specified by Boost.Config BOOST_NO_CXX11_HDR_EXCEPTION), unless enable_current_exception was used at the time the currently handled exception object was passed to throw. Whenever current_exception fails to properly copy the current exception object, it returns an exception_ptr to an object of type that is as close as possible to the original exception type, using unknown_exception as a final fallback. All such types derive from boost::exception, and:
diff --git a/include/boost/exception/detail/exception_ptr.hpp b/include/boost/exception/detail/exception_ptr.hpp
index d4eba62..c106ce2 100644
--- a/include/boost/exception/detail/exception_ptr.hpp
+++ b/include/boost/exception/detail/exception_ptr.hpp
@@ -412,11 +412,14 @@ boost
{
return exception_detail::current_exception_std_exception(e);
}
+#ifdef BOOST_NO_CXX11_HDR_EXCEPTION
+ // this case can be handled losslesly with std::current_exception() (see below)
catch(
std::exception & e )
{
return exception_detail::current_exception_unknown_std_exception(e);
}
+#endif
catch(
boost::exception & e )
{
@@ -425,7 +428,22 @@ boost
catch(
... )
{
+#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
+ try
+ {
+ // wrap the std::exception_ptr in a clone-enabled Boost.Exception object
+ exception_detail::clone_base const& base =
+ boost::enable_current_exception(std::current_exception());
+ return exception_ptr(shared_ptr(base.clone()));
+ }
+ catch(
+ ...)
+ {
+ return exception_detail::current_exception_unknown_exception();
+ }
+#else
return exception_detail::current_exception_unknown_exception();
+#endif
}
}
}
@@ -461,7 +479,20 @@ boost
rethrow_exception( exception_ptr const & p )
{
BOOST_ASSERT(p);
+#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
+ try
+ {
+ p.ptr_->rethrow();
+ }
+ catch(
+ const std::exception_ptr& std_ep)
+ {
+ // if an std::exception_ptr was wrapped above then rethrow it
+ std::rethrow_exception(std_ep);
+ }
+#else
p.ptr_->rethrow();
+#endif
BOOST_ASSERT(0);
#if defined(UNDER_CE)
// some CE platforms don't define ::abort()
diff --git a/test/unknown_exception_test.cpp b/test/unknown_exception_test.cpp
index bf474ba..8bed4c6 100644
--- a/test/unknown_exception_test.cpp
+++ b/test/unknown_exception_test.cpp
@@ -38,6 +38,25 @@ throw_unknown_exception()
throw test_exception();
}
+struct
+user_defined_exception
+ {
+ user_defined_exception(int d):data(d){}
+ int data;
+ };
+
+void
+throw_user_defined_exception()
+ {
+ throw user_defined_exception(42);
+ }
+
+void
+throw_builtin_exception()
+ {
+ throw 42;
+ }
+
int
main()
{
@@ -138,5 +157,115 @@ main()
BOOST_TEST(false);
}
}
+ try
+ {
+ throw_user_defined_exception();
+ }
+ catch(
+ ... )
+ {
+ boost::exception_ptr ep=boost::current_exception();
+ try
+ {
+ rethrow_exception(ep);
+ }
+#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
+ catch(
+ user_defined_exception & x)
+ {
+ //Yay! std::current_exception to the rescue!
+ BOOST_TEST( 42==x.data );
+ }
+#else
+ catch(
+ boost::unknown_exception & )
+ {
+ //Boo! user defined exception was transported as a boost::unknown_exception
+ }
+#endif
+ catch(
+ ... )
+ {
+ BOOST_TEST(false);
+ }
+ try
+ {
+ rethrow_exception(ep);
+ }
+#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
+ catch(
+ user_defined_exception & x)
+ {
+ //Yay! std::current_exception to the rescue!
+ BOOST_TEST( 42==x.data );
+ }
+#else
+ catch(
+ boost::unknown_exception & )
+ {
+ //Boo! user defined exception was transported as a boost::unknown_exception
+ }
+#endif
+ catch(
+ ... )
+ {
+ BOOST_TEST(false);
+ }
+ }
+ try
+ {
+ throw_builtin_exception();
+ }
+ catch(
+ ... )
+ {
+ boost::exception_ptr ep=boost::current_exception();
+ try
+ {
+ rethrow_exception(ep);
+ }
+#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
+ catch(
+ int & x)
+ {
+ //Yay! std::current_exception to the rescue!
+ BOOST_TEST( 42==x );
+ }
+#else
+ catch(
+ boost::unknown_exception & )
+ {
+ //Boo! builtin exception was transported as a boost::unknown_exception
+ }
+#endif
+ catch(
+ ... )
+ {
+ BOOST_TEST(false);
+ }
+ try
+ {
+ rethrow_exception(ep);
+ }
+#ifndef BOOST_NO_CXX11_HDR_EXCEPTION
+ catch(
+ int & x)
+ {
+ //Yay! std::current_exception to the rescue!
+ BOOST_TEST( 42==x );
+ }
+#else
+ catch(
+ boost::unknown_exception & )
+ {
+ //Boo! builtin exception was transported as a boost::unknown_exception
+ }
+#endif
+ catch(
+ ... )
+ {
+ BOOST_TEST(false);
+ }
+ }
return boost::report_errors();
}