diff --git a/doc/BOOST_THROW_EXCEPTION.html b/doc/BOOST_THROW_EXCEPTION.html new file mode 100644 index 0000000..d96f297 --- /dev/null +++ b/doc/BOOST_THROW_EXCEPTION.html @@ -0,0 +1,57 @@ + + + + + BOOST_THROW_EXCEPTION + + + +
+
+
+
+ +

Boost Exception

+
+ + + +

BOOST_THROW_EXCEPTION

+
+

#include <boost/throw_exception.hpp>

+
#if !defined( BOOST_NO_EXCEPTIONS ) && !defined( BOOST_EXCEPTION_DISABLE )
+    #include <boost/exception/exception.hpp>
+    #include <boost/current_function.hpp>
+    #define BOOST_THROW_EXCEPTION(x)\
+        ::boost::throw_exception( ::boost::enable_error_info(x) <<\
+        ::boost::throw_function(BOOST_CURRENT_FUNCTION) <<\
+        ::boost::throw_file(__FILE__) <<\
+        ::boost::throw_line((int)__LINE__) )
+#else
+    #define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(x)
+#endif
+

This macro takes an exception object, records BOOST_CURRENT_FUNCTION, __FILE__ and __LINE__ in it, and forwards it to throw_exception. To recover this information at the catch site, use get_error_info; the information is also included in the message returned by diagnostic_information.

+
+ + + + +
+
+
+ + diff --git a/doc/throw_exception.html b/doc/throw_exception.html index 27e7b17..f4eb745 100644 --- a/doc/throw_exception.html +++ b/doc/throw_exception.html @@ -25,16 +25,12 @@
namespace
 boost
     {
-    #ifdef BOOST_NO_EXCEPTIONS
-    
+#ifdef BOOST_NO_EXCEPTIONS
     void throw_exception( std::exception const & e ); // user defined
-    
-    #else
-    
+#else
     template <class E>
     void throw_exception( E const & e );
-    
-    #endif
+#endif
     }

Requirements:

E must derive publicly from std::exception.

@@ -44,8 +40,10 @@ boost

See Also:

-
Boost Exception
+
diff --git a/include/boost/exception/exception.hpp b/include/boost/exception/exception.hpp index d128cd3..3d5383d 100644 --- a/include/boost/exception/exception.hpp +++ b/include/boost/exception/exception.hpp @@ -6,115 +6,390 @@ #ifndef UUID_274DA366004E11DCB1DDFE2E56D89593 #define UUID_274DA366004E11DCB1DDFE2E56D89593 -#include -#include -#include -#include -#include - namespace boost { - template + namespace + exception_detail + { + template + class + refcount_ptr + { + public: + + refcount_ptr(): + px_(0) + { + } + + ~refcount_ptr() + { + release(); + } + + refcount_ptr( refcount_ptr const & x ): + px_(x.px_) + { + add_ref(); + } + + refcount_ptr & + operator=( refcount_ptr const & x ) + { + adopt(x.px_); + return *this; + } + + void + adopt( T * px ) + { + release(); + px_=px; + add_ref(); + } + + T * + get() const + { + return px_; + } + + private: + + T * px_; + + void + add_ref() + { + if( px_ ) + px_->add_ref(); + } + + void + release() + { + if( px_ ) + px_->release(); + } + }; + } + + //////////////////////////////////////////////////////////////////////// + + template + class error_info; + + typedef error_info throw_function; + typedef error_info throw_file; + typedef error_info throw_line; + + template <> + class + error_info + { + public: + typedef char const * value_type; + value_type v_; + explicit + error_info( value_type v ): + v_(v) + { + } + }; + + template <> + class + error_info + { + public: + typedef char const * value_type; + value_type v_; + explicit + error_info( value_type v ): + v_(v) + { + } + }; + + template <> + class + error_info + { + public: + typedef int value_type; + value_type v_; + explicit + error_info( value_type v ): + v_(v) + { + } + }; + + template + E const & operator<<( E const &, error_info const & ); + + class exception; + + template class shared_ptr; namespace exception_detail { class error_info_base; + struct type_info_; struct - error_info_container: - public exception_detail::counted_base + error_info_container { - virtual char const * diagnostic_information( char const *, std::type_info const & ) const = 0; - virtual shared_ptr get( std::type_info const & ) const = 0; - virtual void set( shared_ptr const & ) = 0; + virtual char const * diagnostic_information() const = 0; + virtual shared_ptr get( type_info_ const & ) const = 0; + virtual void set( shared_ptr const &, type_info_ const & ) = 0; + virtual void add_ref() const = 0; + virtual void release() const = 0; + + protected: + + virtual + ~error_info_container() throw() + { + } }; + + template + struct get_info; + + template <> + struct get_info; + + template <> + struct get_info; + + template <> + struct get_info; + + char const * get_diagnostic_information( exception const & ); } - template - class error_info; - - template - E const & operator<<( E const &, error_info const & ); - - template - shared_ptr get_error_info( E const & ); - class exception { - public: - - virtual - char const * - diagnostic_information() const throw() - { - return _diagnostic_information(0); - } - protected: - exception() + exception(): + throw_function_(0), + throw_file_(0), + throw_line_(-1) { } - exception( exception const & e ): - data_(e.data_) - { - } - - char const * - _diagnostic_information( char const * std_what ) const throw() - { - if( data_ ) - try - { - char const * w = data_->diagnostic_information(std_what,typeid(*this)); - BOOST_ASSERT(0!=w); - return w; - } - catch(...) - { - } - return std_what ? std_what : typeid(*this).name(); - } - -#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1500) ) - //Force class exception to be abstract. - //Otherwise, MSVC bug allows throw exception(), even though the copy constructor is protected. - virtual ~exception() throw()=0; -#else -#if BOOST_WORKAROUND( __GNUC__, BOOST_TESTED_AT(4) ) - virtual //Disable bogus GCC warning. -#endif - ~exception() throw() +#ifdef __HP_aCC + //On HP aCC, this protected copy constructor prevents throwing boost::exception. + //On all other platforms, the same effect is achieved by the pure virtual destructor. + exception( exception const & x ) throw(): + data_(x.data_), + throw_function_(x.throw_function_), + throw_file_(x.throw_file_), + throw_line_(x.throw_line_) { } #endif + virtual ~exception() throw() +#ifndef __HP_aCC + = 0 //Workaround for HP aCC, =0 incorrectly leads to link errors. +#endif + ; + private: - shared_ptr get( std::type_info const & ) const; - void set( shared_ptr const & ) const; + template + friend + E const & + operator<<( E const & x, throw_function const & y ) + { + x.throw_function_=y.v_; + return x; + } + + template + friend + E const & + operator<<( E const & x, throw_file const & y ) + { + x.throw_file_=y.v_; + return x; + } + + template + friend + E const & + operator<<( E const & x, throw_line const & y ) + { + x.throw_line_=y.v_; + return x; + } + + friend char const * exception_detail::get_diagnostic_information( exception const & ); template friend E const & operator<<( E const &, error_info const & ); - template - friend shared_ptr get_error_info( E const & ); + template + friend struct exception_detail::get_info; + friend struct exception_detail::get_info; + friend struct exception_detail::get_info; + friend struct exception_detail::get_info; - intrusive_ptr mutable data_; + mutable exception_detail::refcount_ptr data_; + mutable char const * throw_function_; + mutable char const * throw_file_; + mutable int throw_line_; }; -#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1500) ) //See above. inline exception:: ~exception() throw() { } -#endif + + //////////////////////////////////////////////////////////////////////// + + namespace + exception_detail + { + template + struct + error_info_injector: + public T, + public exception + { + explicit + error_info_injector( T const & x ): + T(x) + { + } + + ~error_info_injector() throw() + { + } + }; + + struct large_size { char c[256]; }; + large_size dispatch( exception * ); + + struct small_size { }; + small_size dispatch( void * ); + + template + struct enable_error_info_helper; + + template + struct + enable_error_info_helper + { + typedef T type; + }; + + template + struct + enable_error_info_helper + { + typedef error_info_injector type; + }; + + template + struct + enable_error_info_return_type + { + typedef typename enable_error_info_helper::type type; + }; + } + + template + inline + typename + exception_detail::enable_error_info_return_type::type + enable_error_info( T const & x ) + { + return typename exception_detail::enable_error_info_return_type::type(x); + } + + //////////////////////////////////////////////////////////////////////// + + namespace + exception_detail + { + class + clone_base + { + public: + + virtual clone_base const * clone() const = 0; + virtual void rethrow() const = 0; + + virtual + ~clone_base() throw() + { + } + }; + + inline + void + copy_boost_exception( exception * a, exception const * b ) + { + *a = *b; + } + + inline + void + copy_boost_exception( void *, void const * ) + { + } + + template + class + clone_impl: + public T, + public clone_base + { + public: + + explicit + clone_impl( T const & x ): + T(x) + { + copy_boost_exception(this,&x); + } + + ~clone_impl() throw() + { + } + + private: + + clone_base const * + clone() const + { + return new clone_impl(*this); + } + + void + rethrow() const + { + throw*this; + } + }; + } + + template + inline + exception_detail::clone_impl + enable_current_exception( T const & x ) + { + return exception_detail::clone_impl(x); + } } #endif diff --git a/include/boost/throw_exception.hpp b/include/boost/throw_exception.hpp index dc468f2..5d00854 100644 --- a/include/boost/throw_exception.hpp +++ b/include/boost/throw_exception.hpp @@ -24,11 +24,7 @@ #include #include -#if !defined( BOOST_EXCEPTION_DISABLE ) && defined( BOOST_NO_TYPEID ) -# define BOOST_EXCEPTION_DISABLE -#endif - -#if !defined( BOOST_EXCEPTION_DISABLE ) && defined( __BORLANDC__ ) && BOOST_WORKAROUND( __BORLANDC__, < 0x590 ) +#if !defined( BOOST_EXCEPTION_DISABLE ) && defined( __BORLANDC__ ) && BOOST_WORKAROUND( __BORLANDC__, <= 0x593 ) # define BOOST_EXCEPTION_DISABLE #endif @@ -37,8 +33,14 @@ #endif #if !defined( BOOST_NO_EXCEPTIONS ) && !defined( BOOST_EXCEPTION_DISABLE ) -# include -# include +# include +# include +# define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(::boost::enable_error_info(x) <<\ + ::boost::throw_function(BOOST_CURRENT_FUNCTION) <<\ + ::boost::throw_file(__FILE__) <<\ + ::boost::throw_line((int)__LINE__)) +#else +# define BOOST_THROW_EXCEPTION(x) ::boost::throw_exception(x) #endif namespace boost diff --git a/test/1-throw_exception_test.cpp b/test/1-throw_exception_test.cpp new file mode 100644 index 0000000..5719e80 --- /dev/null +++ b/test/1-throw_exception_test.cpp @@ -0,0 +1,29 @@ +//Copyright (c) 2006-2008 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 + +class my_exception: public std::exception { }; + +int +main() + { + try + { + boost::throw_exception(my_exception()); + BOOST_ERROR("boost::throw_exception failed to throw."); + } + catch( + my_exception & ) + { + } + catch( + ... ) + { + BOOST_ERROR("boost::throw_exception malfunction."); + } + return boost::report_errors(); + } diff --git a/test/2-throw_exception_no_exceptions_test.cpp b/test/2-throw_exception_no_exceptions_test.cpp new file mode 100644 index 0000000..aca309d --- /dev/null +++ b/test/2-throw_exception_no_exceptions_test.cpp @@ -0,0 +1,30 @@ +//Copyright (c) 2006-2008 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) + +#define BOOST_NO_EXCEPTIONS +#include +#include + +class my_exception: public std::exception { }; + +bool called=false; + +namespace +boost + { + void + throw_exception( std::exception const & ) + { + called=true; + } + } + +int +main() + { + boost::throw_exception(my_exception()); + BOOST_TEST(called); + return boost::report_errors(); + } diff --git a/test/3-throw_exception_no_integration_test.cpp b/test/3-throw_exception_no_integration_test.cpp new file mode 100644 index 0000000..16b3d8c --- /dev/null +++ b/test/3-throw_exception_no_integration_test.cpp @@ -0,0 +1,30 @@ +//Copyright (c) 2006-2008 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) + +#define BOOST_EXCEPTION_DISABLE +#include +#include + +class my_exception: public std::exception { }; + +int +main() + { + try + { + boost::throw_exception(my_exception()); + BOOST_ERROR("boost::throw_exception failed to throw."); + } + catch( + my_exception & ) + { + } + catch( + ... ) + { + BOOST_ERROR("boost::throw_exception malfunction."); + } + return boost::report_errors(); + } diff --git a/test/4-throw_exception_no_both_test.cpp b/test/4-throw_exception_no_both_test.cpp new file mode 100644 index 0000000..4c58605 --- /dev/null +++ b/test/4-throw_exception_no_both_test.cpp @@ -0,0 +1,31 @@ +//Copyright (c) 2006-2008 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) + +#define BOOST_NO_EXCEPTIONS +#define BOOST_EXCEPTION_DISABLE +#include +#include + +class my_exception: public std::exception { }; + +bool called=false; + +namespace +boost + { + void + throw_exception( std::exception const & ) + { + called=true; + } + } + +int +main() + { + boost::throw_exception(my_exception()); + BOOST_TEST(called); + return boost::report_errors(); + }