diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 new file mode 100644 index 0000000..0cf2a62 --- /dev/null +++ b/build/Jamfile.v2 @@ -0,0 +1,11 @@ +# Boost Exception Library build Jamfile +# +# Copyright (c) 2006-2009 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) + +alias boost_exception ; +lib boost_exception : ../src/clone_current_exception_msvc.cpp : msvc ; + +boost-install boost_exception ; diff --git a/include/boost/exception/detail/clone_current_exception.hpp b/include/boost/exception/detail/clone_current_exception.hpp new file mode 100644 index 0000000..28e3377 --- /dev/null +++ b/include/boost/exception/detail/clone_current_exception.hpp @@ -0,0 +1,44 @@ +//Copyright (c) 2006-2009 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) + +#ifndef UUID_81522C0EB56511DFAB613DB0DFD72085 +#define UUID_81522C0EB56511DFAB613DB0DFD72085 + +#ifdef BOOST_NO_EXCEPTIONS +#error This header requires exception handling to be enabled. +#endif + +namespace +boost + { + namespace + exception_detail + { + namespace + clone_current_exception_result + { + int const success=0; + int const bad_alloc=1; + int const bad_exception=2; + int const not_supported=3; + } + + class clone_base; + int clone_current_exception_msvc_x86( clone_base const * & cloned ); + + inline + int + clone_current_exception( clone_base const * & cloned ) + { +#if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && defined(_M_IX86) && !defined(_M_X64) + return clone_current_exception_msvc_x86(cloned); +#else + return clone_current_exception_result::not_supported; +#endif + } + } + } + +#endif diff --git a/include/boost/exception/detail/exception_ptr.hpp b/include/boost/exception/detail/exception_ptr.hpp index 0510fe2..b1731ee 100644 --- a/include/boost/exception/detail/exception_ptr.hpp +++ b/include/boost/exception/detail/exception_ptr.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,10 +29,42 @@ namespace boost { - typedef shared_ptr exception_ptr; - + class exception_ptr; + BOOST_ATTRIBUTE_NORETURN void rethrow_exception( exception_ptr const & ); exception_ptr current_exception(); + class + exception_ptr + { + typedef boost::shared_ptr impl; + impl ptr_; + friend void rethrow_exception( exception_ptr const & ); + typedef exception_detail::clone_base const * (impl::*unspecified_bool_type)() const; + public: + exception_ptr() + { + } + explicit + exception_ptr( impl const & ptr ): + ptr_(ptr) + { + } + bool + operator==( exception_ptr const & other ) const + { + return ptr_==other.ptr_; + } + bool + operator!=( exception_ptr const & other ) const + { + return ptr_!=other.ptr_; + } + operator unspecified_bool_type() const + { + return ptr_?&impl::get:0; + } + }; + template inline exception_ptr @@ -67,35 +100,49 @@ boost boost::exception, std::bad_alloc { + ~bad_alloc_() throw() { } }; - template + struct + bad_exception_: + boost::exception, + std::bad_exception + { + ~bad_exception_() throw() { } + }; + + template exception_ptr - get_bad_alloc() + get_static_exception_object() { - bad_alloc_ ba; - exception_detail::clone_impl c(ba); + Exception ba; + exception_detail::clone_impl c(ba); c << throw_function(BOOST_CURRENT_FUNCTION) << throw_file(__FILE__) << throw_line(__LINE__); - static exception_ptr ep(new exception_detail::clone_impl(c)); + static exception_ptr ep(shared_ptr(new exception_detail::clone_impl(c))); return ep; } - template + template struct - exception_ptr_bad_alloc + exception_ptr_static_exception_object { static exception_ptr const e; }; - template + template exception_ptr const - exception_ptr_bad_alloc:: - e = get_bad_alloc(); + exception_ptr_static_exception_object:: + e = get_static_exception_object(); } +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif +#endif class unknown_exception: public boost::exception, @@ -135,6 +182,11 @@ boost #endif } }; +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif +#endif namespace exception_detail @@ -244,101 +296,131 @@ boost exception_ptr current_exception_impl() { - try + exception_detail::clone_base const * e=0; + switch( + exception_detail::clone_current_exception(e) ) { - throw; - } - catch( - exception_detail::clone_base & e ) - { - return exception_ptr(e.clone()); - } - catch( - std::domain_error & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::invalid_argument & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::length_error & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::out_of_range & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::logic_error & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::range_error & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::overflow_error & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::underflow_error & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::ios_base::failure & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::runtime_error & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::bad_alloc & e ) - { - return exception_detail::current_exception_std_exception(e); - } + case exception_detail::clone_current_exception_result:: + success: + { + BOOST_ASSERT(e!=0); + return exception_ptr(shared_ptr(e)); + } + case exception_detail::clone_current_exception_result:: + bad_alloc: + { + BOOST_ASSERT(!e); + return exception_detail::exception_ptr_static_exception_object::e; + } + case exception_detail::clone_current_exception_result:: + bad_exception: + { + BOOST_ASSERT(!e); + return exception_detail::exception_ptr_static_exception_object::e; + } + default: + BOOST_ASSERT(0); + case exception_detail::clone_current_exception_result:: + not_supported: + { + BOOST_ASSERT(!e); + try + { + throw; + } + catch( + exception_detail::clone_base & e ) + { + return exception_ptr(shared_ptr(e.clone())); + } + catch( + std::domain_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::invalid_argument & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::length_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::out_of_range & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::logic_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::range_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::overflow_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::underflow_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::ios_base::failure & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::runtime_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::bad_alloc & e ) + { + return exception_detail::current_exception_std_exception(e); + } #ifndef BOOST_NO_TYPEID - catch( - std::bad_cast & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::bad_typeid & e ) - { - return exception_detail::current_exception_std_exception(e); - } + catch( + std::bad_cast & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::bad_typeid & e ) + { + return exception_detail::current_exception_std_exception(e); + } #endif - catch( - std::bad_exception & e ) - { - return exception_detail::current_exception_std_exception(e); - } - catch( - std::exception & e ) - { - return exception_detail::current_exception_unknown_std_exception(e); - } - catch( - boost::exception & e ) - { - return exception_detail::current_exception_unknown_boost_exception(e); - } - catch( - ... ) - { - return exception_detail::current_exception_unknown_exception(); + catch( + std::bad_exception & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::exception & e ) + { + return exception_detail::current_exception_unknown_std_exception(e); + } + catch( + boost::exception & e ) + { + return exception_detail::current_exception_unknown_boost_exception(e); + } + catch( + ... ) + { + return exception_detail::current_exception_unknown_exception(); + } + } } } } @@ -348,7 +430,6 @@ boost current_exception() { exception_ptr ret; - BOOST_ASSERT(!ret); try { ret=exception_detail::current_exception_impl(); @@ -356,36 +437,24 @@ boost catch( std::bad_alloc & ) { - ret=exception_detail::exception_ptr_bad_alloc<42>::e; + ret=exception_detail::exception_ptr_static_exception_object::e; } catch( ... ) { - try - { - ret=exception_detail::current_exception_std_exception(std::bad_exception()); - } - catch( - std::bad_alloc & ) - { - ret=exception_detail::exception_ptr_bad_alloc<42>::e; - } - catch( - ... ) - { - BOOST_ASSERT(0); - } + ret=exception_detail::exception_ptr_static_exception_object::e; } BOOST_ASSERT(ret); return ret; } + BOOST_ATTRIBUTE_NORETURN inline void rethrow_exception( exception_ptr const & p ) { BOOST_ASSERT(p); - p->rethrow(); + p.ptr_->rethrow(); } inline diff --git a/include/boost/exception/detail/type_info.hpp b/include/boost/exception/detail/type_info.hpp index 9ab1c57..92f8464 100644 --- a/include/boost/exception/detail/type_info.hpp +++ b/include/boost/exception/detail/type_info.hpp @@ -53,11 +53,11 @@ boost struct type_info_ { - detail::sp_typeinfo const & type_; + detail::sp_typeinfo const * type_; explicit type_info_( detail::sp_typeinfo const & type ): - type_(type) + type_(&type) { } @@ -65,7 +65,7 @@ boost bool operator<( type_info_ const & a, type_info_ const & b ) { - return 0!=(a.type_.before(b.type_)); + return 0!=(a.type_->before(*b.type_)); } }; } diff --git a/include/boost/exception/diagnostic_information.hpp b/include/boost/exception/diagnostic_information.hpp index 2297676..7cbb355 100644 --- a/include/boost/exception/diagnostic_information.hpp +++ b/include/boost/exception/diagnostic_information.hpp @@ -137,7 +137,7 @@ boost } #ifndef BOOST_NO_RTTI tmp << std::string("Dynamic exception type: ") << - units::detail::demangle((be?(BOOST_EXCEPTION_DYNAMIC_TYPEID(*be)):(BOOST_EXCEPTION_DYNAMIC_TYPEID(*se))).type_.name()) << '\n'; + units::detail::demangle((be?(BOOST_EXCEPTION_DYNAMIC_TYPEID(*be)):(BOOST_EXCEPTION_DYNAMIC_TYPEID(*se))).type_->name()) << '\n'; #endif if( with_what && se ) tmp << "std::exception::what: " << wh << '\n'; diff --git a/include/boost/exception/errinfo_nested_exception.hpp b/include/boost/exception/errinfo_nested_exception.hpp index e4e75d9..c3299d1 100644 --- a/include/boost/exception/errinfo_nested_exception.hpp +++ b/include/boost/exception/errinfo_nested_exception.hpp @@ -9,10 +9,9 @@ namespace boost { - namespace exception_detail { class clone_base; }; + namespace exception_detail { class clone_base; } template class error_info; - template class shared_ptr; - typedef shared_ptr exception_ptr; + class exception_ptr; typedef error_info errinfo_nested_exception; } diff --git a/include/boost/exception/exception.hpp b/include/boost/exception/exception.hpp index adaac68..6e9d405 100644 --- a/include/boost/exception/exception.hpp +++ b/include/boost/exception/exception.hpp @@ -189,6 +189,11 @@ boost E const & set_info( E const &, throw_line const & ); } +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif +#endif class exception { @@ -250,6 +255,11 @@ boost mutable char const * throw_file_; mutable int throw_line_; }; +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif +#endif inline exception:: @@ -334,7 +344,7 @@ boost struct enable_error_info_return_type { - typedef typename enable_error_info_helper::type type; + typedef typename enable_error_info_helper(0)))>::type type; }; } diff --git a/src/clone_current_exception_msvc.cpp b/src/clone_current_exception_msvc.cpp new file mode 100644 index 0000000..5dda846 --- /dev/null +++ b/src/clone_current_exception_msvc.cpp @@ -0,0 +1,295 @@ +//Copyright (c) 2006-2009 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) + +//This MSVC-specific cpp file implements non-intrusive cloning of exception objects. +//Based on an exception_ptr implementation by Anthony Williams. + +#ifdef BOOST_NO_EXCEPTIONS +#error This file requires exception handling to be enabled. +#endif + +#if defined(_MSC_VER) && defined(_M_IX86) && !defined(_M_X64) + +#include +#include +#include +#ifndef BOOST_NO_RTTI +#include +#endif +#include +#include + +namespace + { + unsigned const exception_maximum_parameters=15; + unsigned const exception_noncontinuable=1; + +#if _MSC_VER==1310 + int const exception_info_offset=0x74; +#elif (_MSC_VER==1400 || _MSC_VER==1500) + int const exception_info_offset=0x80; +#else + int const exception_info_offset=-1; +#endif + + struct + exception_record + { + unsigned long ExceptionCode; + unsigned long ExceptionFlags; + exception_record * ExceptionRecord; + void * ExceptionAddress; + unsigned long NumberParameters; + ULONG_PTR ExceptionInformation[exception_maximum_parameters]; + }; + + struct + exception_pointers + { + exception_record * ExceptionRecord; + void * ContextRecord; + }; + + unsigned const cpp_exception_code=0xE06D7363; + unsigned const cpp_exception_magic_flag=0x19930520; + unsigned const cpp_exception_parameter_count=3; + + struct + dummy_exception_type + { + }; + + typedef int(dummy_exception_type::*normal_copy_constructor_ptr)(void * src); + typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr)(void * src,void * dst); + typedef void (dummy_exception_type::*destructor_ptr)(); + + union + cpp_copy_constructor + { + normal_copy_constructor_ptr normal_copy_constructor; + copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base; + }; + + enum + cpp_type_flags + { + class_is_simple_type=1, + class_has_virtual_base=4 + }; + + struct + cpp_type_info + { + unsigned flags; +#ifndef BOOST_NO_RTTI + void const * type_info; +#else + std::type_info * type_info; +#endif + int this_offset; + int vbase_descr; + int vbase_offset; + unsigned long size; + cpp_copy_constructor copy_constructor; + }; + + struct + cpp_type_info_table + { + unsigned count; + const cpp_type_info * info[1]; + }; + + struct + cpp_exception_type + { + unsigned flags; + destructor_ptr destructor; + void(*custom_handler)(); + cpp_type_info_table const * type_info_table; + }; + + struct + exception_object_deleter + { + cpp_exception_type const & et_; + + exception_object_deleter( cpp_exception_type const & et ): + et_(et) + { + } + + void + operator()( void * obj ) + { + BOOST_ASSERT(obj!=0); + dummy_exception_type * dummy_exception_ptr=reinterpret_cast(obj); + (dummy_exception_ptr->*(et_.destructor))(); + free(obj); + } + }; + + cpp_type_info const & + get_cpp_type_info( cpp_exception_type const & et ) + { + cpp_type_info const * ti = et.type_info_table->info[0]; + BOOST_ASSERT(ti!=0); + return *ti; + } + + void + copy_msvc_exception( void * dst, void * src, cpp_type_info const & ti ) + { + if( !(ti.flags & class_is_simple_type) && ti.copy_constructor.normal_copy_constructor ) + { + dummy_exception_type * dummy_exception_ptr = reinterpret_cast(dst); + if( ti.flags & class_has_virtual_base ) + (dummy_exception_ptr->*(ti.copy_constructor.copy_constructor_with_virtual_base))(src,dst); + else + (dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src); + } + else + memmove(dst,src,ti.size); + } + + boost::shared_ptr + clone_msvc_exception( void * src, cpp_exception_type const & et ) + { + assert(src!=0); + cpp_type_info const & ti=get_cpp_type_info(et); + if( void * dst = malloc(ti.size) ) + { + try + { + copy_msvc_exception(dst,src,ti); + } + catch( + ... ) + { + free(dst); + throw; + } + return boost::shared_ptr(dst,exception_object_deleter(et)); + } + else + throw std::bad_alloc(); + } + + class + cloned_exception: + public boost::exception_detail::clone_base + { + cloned_exception( cloned_exception const & ); + cloned_exception & operator=( cloned_exception const & ); + + cpp_exception_type const & et_; + boost::shared_ptr exc_; + + public: + + cloned_exception( void * exc, cpp_exception_type const & et ): + et_(et), + exc_(clone_msvc_exception(exc,et_)) + { + } + + ~cloned_exception() throw() + { + } + + boost::exception_detail::clone_base const * + clone() const + { + return new cloned_exception(exc_.get(),et_); + } + + void + rethrow() const + { + cpp_type_info const & ti=get_cpp_type_info(et_); + void * dst = _alloca(ti.size); + copy_msvc_exception(dst,exc_.get(),ti); + ULONG_PTR args[cpp_exception_parameter_count]; + args[0]=cpp_exception_magic_flag; + args[1]=reinterpret_cast(dst); + args[2]=reinterpret_cast(&et_); + RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args); + } + }; + + bool + is_cpp_exception( EXCEPTION_RECORD const * record ) + { + return record && + (record->ExceptionCode==cpp_exception_code) && + (record->NumberParameters==cpp_exception_parameter_count) && + (record->ExceptionInformation[0]==cpp_exception_magic_flag); + } + + unsigned long + exception_cloning_filter( int & result, boost::exception_detail::clone_base const * & ptr, void * info_ ) + { + BOOST_ASSERT(exception_info_offset>=0); + BOOST_ASSERT(info_!=0); + EXCEPTION_POINTERS * info=reinterpret_cast(info_); + EXCEPTION_RECORD * record=info->ExceptionRecord; + if( is_cpp_exception(record) ) + { + if( !record->ExceptionInformation[2] ) + record = *reinterpret_cast(reinterpret_cast(_errno())+exception_info_offset); + if( is_cpp_exception(record) && record->ExceptionInformation[2] ) + try + { + ptr = new cloned_exception( + reinterpret_cast(record->ExceptionInformation[1]), + *reinterpret_cast(record->ExceptionInformation[2])); + result = boost::exception_detail::clone_current_exception_result::success; + } + catch( + std::bad_alloc & ) + { + result = boost::exception_detail::clone_current_exception_result::bad_alloc; + } + catch( + ... ) + { + result = boost::exception_detail::clone_current_exception_result::bad_exception; + } + } + return EXCEPTION_EXECUTE_HANDLER; + } + } + +namespace +boost + { + namespace + exception_detail + { + int + clone_current_exception_msvc_x86( clone_base const * & cloned ) + { + BOOST_ASSERT(!cloned); + int result = clone_current_exception_result::not_supported; + if( exception_info_offset>=0 ) + { + clone_base const * ptr=0; + __try + { + throw; + } + __except(exception_cloning_filter(result,ptr,GetExceptionInformation())) + { + } + if( result==clone_current_exception_result::success ) + cloned=ptr; + } + BOOST_ASSERT(result!=clone_current_exception_result::success || cloned); + return result; + } + } + } + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0d45c2f..b989171 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -7,7 +7,13 @@ import testing ; -project : requirements on ; +project + : requirements + static + on + /boost//exception + BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR + ; #to_string @@ -37,6 +43,7 @@ run current_exception_cast_test.cpp ; run no_exceptions_test.cpp : : : off ; run errinfos_test.cpp ; run exception_ptr_test.cpp /boost//thread : : : multi ; + compile-fail exception_fail.cpp ; compile-fail throw_exception_fail.cpp ; compile-fail error_info_const_fail.cpp ; diff --git a/test/cloning_test.cpp b/test/cloning_test.cpp index 77abbe3..ec10976 100644 --- a/test/cloning_test.cpp +++ b/test/cloning_test.cpp @@ -146,6 +146,10 @@ test_std_exception() #endif } catch( + T & ) + { + } + catch( ... ) { BOOST_TEST(false); @@ -176,7 +180,7 @@ test_std_exception_what() catch( T & x ) { - BOOST_TEST(std::string("what")==x.what()); + BOOST_TEST(std::string(x.what()).find("what")!=std::string::npos); boost::exception_ptr p = boost::current_exception(); BOOST_TEST(!(p==boost::exception_ptr())); BOOST_TEST(p!=boost::exception_ptr()); @@ -189,7 +193,7 @@ test_std_exception_what() catch( T & x ) { - BOOST_TEST(std::string("what")==x.what()); + BOOST_TEST(std::string(x.what()).find("what")!=std::string::npos); } catch( ... ) @@ -216,6 +220,10 @@ test_std_exception_what() #endif } catch( + T & ) + { + } + catch( ... ) { BOOST_TEST(false); @@ -385,6 +393,11 @@ main() BOOST_TEST(false); } catch( + derives_std_exception & ) + { + //Yay! Non-intrusive cloning supported! + } + catch( boost::unknown_exception & e ) { #ifndef BOOST_NO_RTTI @@ -434,6 +447,14 @@ main() BOOST_TEST(false); } catch( + derives_std_boost_exception & x ) + { + //Yay! Non-intrusive cloning supported! + BOOST_TEST(boost::get_error_info(x)); + if( int const * p=boost::get_error_info(x) ) + BOOST_TEST(*p==42); + } + catch( boost::unknown_exception & x ) { BOOST_TEST(boost::get_error_info(x)); @@ -495,6 +516,14 @@ main() BOOST_TEST(false); } catch( + derives_boost_exception & x ) + { + //Yay! Non-intrusive cloning supported! + BOOST_TEST(boost::get_error_info(x)); + if( int const * p=boost::get_error_info(x) ) + BOOST_TEST(*p==42); + } + catch( boost::unknown_exception & x ) { BOOST_TEST(boost::get_error_info(x)); diff --git a/test/copy_exception_test.cpp b/test/copy_exception_test.cpp index 84974ce..a88e6d5 100644 --- a/test/copy_exception_test.cpp +++ b/test/copy_exception_test.cpp @@ -6,15 +6,37 @@ #include #include #include +#include #include typedef boost::error_info answer; +boost::detail::atomic_count exc_count(0); + struct err: virtual boost::exception, virtual std::exception { + err() + { + ++exc_count; + } + + err( err const & ) + { + ++exc_count; + } + + virtual + ~err() throw() + { + --exc_count; + } + + private: + + err & operator=( err const & ); }; class @@ -116,7 +138,9 @@ simple_test() int main() { + BOOST_TEST(++exc_count==1); simple_test(); thread_test(); + BOOST_TEST(!--exc_count); return boost::report_errors(); } diff --git a/test/exception_ptr_test.cpp b/test/exception_ptr_test.cpp index 1da2713..4f0eb0c 100644 --- a/test/exception_ptr_test.cpp +++ b/test/exception_ptr_test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -66,7 +67,34 @@ join( thread_handle & t ) rethrow_exception(t.err_); } -struct exc: boost::exception, std::exception { }; +boost::detail::atomic_count exc_count(0); + +struct +exc: + virtual boost::exception, + virtual std::exception + { + exc() + { + ++exc_count; + } + + exc( exc const & ) + { + ++exc_count; + } + + virtual + ~exc() throw() + { + --exc_count; + } + + private: + + exc & operator=( exc const & ); + }; + typedef boost::error_info answer; void @@ -93,6 +121,7 @@ check( boost::shared_ptr const & t ) int main() { + BOOST_TEST(++exc_count==1); try { std::vector< boost::shared_ptr > threads; @@ -109,4 +138,5 @@ main() boost::current_exception_diagnostic_information() << std::endl; return 42; } + BOOST_TEST(!--exc_count); } diff --git a/test/unknown_exception_test.cpp b/test/unknown_exception_test.cpp index 4918b44..bf474ba 100644 --- a/test/unknown_exception_test.cpp +++ b/test/unknown_exception_test.cpp @@ -62,6 +62,15 @@ main() BOOST_TEST(false); } catch( + boost::exception & x ) + { + //Yay! Non-intrusive cloning supported! + if( int const * d=boost::get_error_info(x) ) + BOOST_TEST( 42==*d ); + else + BOOST_TEST(false); + } + catch( ... ) { BOOST_TEST(false); @@ -101,6 +110,11 @@ main() { } catch( + std::exception & ) + { + //Yay! Non-intrusive cloning supported! + } + catch( ... ) { BOOST_TEST(false); @@ -114,6 +128,11 @@ main() { } catch( + std::exception & ) + { + //Yay! Non-intrusive cloning supported! + } + catch( ... ) { BOOST_TEST(false);