Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r65204 - in trunk: boost/exception/detail libs/exception/src libs/exception/test
From: emil_at_[hidden]
Date: 2010-09-02 22:03:18


Author: emildotchevski
Date: 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
New Revision: 65204
URL: http://svn.boost.org/trac/boost/changeset/65204

Log:
Non-intrusive exception_ptr support for msvc 7.1/8.0/9.0 (thanks Anthony Williams)
Text files modified:
   trunk/boost/exception/detail/clone_current_exception.hpp | 3
   trunk/boost/exception/detail/exception_ptr.hpp | 54 ++--
   trunk/libs/exception/src/clone_current_exception_msvc.cpp | 369 ++++++---------------------------------
   trunk/libs/exception/test/Jamfile.v2 | 2
   trunk/libs/exception/test/cloning_test.cpp | 29 +++
   trunk/libs/exception/test/copy_exception_test.cpp | 24 ++
   trunk/libs/exception/test/unknown_exception_test.cpp | 19 ++
   7 files changed, 162 insertions(+), 338 deletions(-)

Modified: trunk/boost/exception/detail/clone_current_exception.hpp
==============================================================================
--- trunk/boost/exception/detail/clone_current_exception.hpp (original)
+++ trunk/boost/exception/detail/clone_current_exception.hpp 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
@@ -21,7 +21,8 @@
             {
             int const success=0;
             int const bad_alloc=1;
- int const not_supported=2;
+ int const bad_exception=2;
+ int const not_supported=3;
             }
 
         class clone_base;

Modified: trunk/boost/exception/detail/exception_ptr.hpp
==============================================================================
--- trunk/boost/exception/detail/exception_ptr.hpp (original)
+++ trunk/boost/exception/detail/exception_ptr.hpp 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
@@ -70,31 +70,38 @@
                 {
                 };
 
- template <int Dummy>
+ struct
+ bad_exception_:
+ boost::exception,
+ std::bad_exception
+ {
+ };
+
+ template <class Exception>
         exception_ptr
- get_bad_alloc()
+ get_static_exception_object()
             {
- bad_alloc_ ba;
- exception_detail::clone_impl<bad_alloc_> c(ba);
+ Exception ba;
+ exception_detail::clone_impl<Exception> c(ba);
             c <<
                 throw_function(BOOST_CURRENT_FUNCTION) <<
                 throw_file(__FILE__) <<
                 throw_line(__LINE__);
- static exception_ptr ep(new exception_detail::clone_impl<bad_alloc_>(c));
+ static exception_ptr ep(new exception_detail::clone_impl<Exception>(c));
             return ep;
             }
 
- template <int Dummy>
+ template <class Exception>
         struct
- exception_ptr_bad_alloc
+ exception_ptr_static_exception_object
             {
             static exception_ptr const e;
             };
 
- template <int Dummy>
+ template <class Exception>
         exception_ptr const
- exception_ptr_bad_alloc<Dummy>::
- e = get_bad_alloc<Dummy>();
+ exception_ptr_static_exception_object<Exception>::
+ e = get_static_exception_object<Exception>();
         }
 
     class
@@ -259,7 +266,13 @@
                 bad_alloc:
                     {
                     BOOST_ASSERT(!e);
- return exception_detail::exception_ptr_bad_alloc<42>::e;
+ return exception_detail::exception_ptr_static_exception_object<bad_alloc_>::e;
+ }
+ case exception_detail::clone_current_exception_result::
+ bad_exception:
+ {
+ BOOST_ASSERT(!e);
+ return exception_detail::exception_ptr_static_exception_object<bad_exception_>::e;
                     }
                 default:
                     BOOST_ASSERT(0);
@@ -346,7 +359,7 @@
                     catch(
                     std::bad_exception & e )
                         {
- return exception_detail::current_exception_std_exception(e);
+ return exception_detail::exception_ptr_static_exception_object<exception_detail::bad_exception_>::e;
                         }
                     catch(
                     std::exception & e )
@@ -380,25 +393,12 @@
         catch(
         std::bad_alloc & )
             {
- ret=exception_detail::exception_ptr_bad_alloc<42>::e;
+ ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_alloc_>::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<exception_detail::bad_exception_>::e;
             }
         BOOST_ASSERT(ret);
         return ret;

Modified: trunk/libs/exception/src/clone_current_exception_msvc.cpp
==============================================================================
--- trunk/libs/exception/src/clone_current_exception_msvc.cpp (original)
+++ trunk/libs/exception/src/clone_current_exception_msvc.cpp 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
@@ -12,6 +12,9 @@
 #include <boost/exception/detail/clone_current_exception.hpp>
 #include <boost/exception/exception.hpp>
 #include <boost/shared_ptr.hpp>
+#ifndef BOOST_NO_RTTI
+#include <typeinfo>
+#endif
 #include <windows.h>
 
 namespace
@@ -21,7 +24,7 @@
 
 #if _MSC_VER==1310
     int const exception_info_offset=0x74;
-#elif _MSC_VER==1400
+#elif (_MSC_VER==1400 || _MSC_VER==1500)
     int const exception_info_offset=0x80;
 #else
     int const exception_info_offset=-1;
@@ -55,7 +58,7 @@
         };
 
     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 * dest);
+ typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr)(void * src,void * dst);
     typedef void (dummy_exception_type::*destructor_ptr)();
 
     union
@@ -76,7 +79,11 @@
     cpp_type_info
         {
         unsigned flags;
- void const * type_info; //std::type_info * type_info;
+#ifndef BOOST_NO_RTTI
+ void const * type_info;
+#else
+ std::type_info * type_info;
+#endif
         int this_offset;
         int vbase_descr;
         int vbase_offset;
@@ -103,47 +110,56 @@
     struct
     exception_object_deleter
         {
- cpp_exception_type const * exception_type_;
- bool run_destructor_;
+ cpp_exception_type const & et_;
 
- exception_object_deleter( cpp_exception_type const * exception_type, bool run_destructor ):
- exception_type_(exception_type),
- run_destructor_(run_destructor)
+ exception_object_deleter( cpp_exception_type const & et ):
+ et_(et)
             {
- BOOST_ASSERT(exception_type_!=0);
             }
 
         void
- operator()( void * exception_object )
+ operator()( void * obj )
             {
- BOOST_ASSERT(exception_object!=0);
- if( run_destructor_ )
- {
- dummy_exception_type * dummy_exception_ptr=reinterpret_cast<dummy_exception_type *>(exception_object);
- (dummy_exception_ptr->*(exception_type_->destructor))();
- }
- free(exception_object);
+ BOOST_ASSERT(obj!=0);
+ dummy_exception_type * dummy_exception_ptr=reinterpret_cast<dummy_exception_type *>(obj);
+ (dummy_exception_ptr->*(et_.destructor))();
+ free(obj);
             }
         };
 
- boost::shared_ptr<void>
- copy_msvc_exception( void * source_object, cpp_exception_type const * exception_type, bool run_destructor )
+ cpp_type_info const &
+ get_cpp_type_info( cpp_exception_type const & et )
         {
- void * exception_object = malloc(exception_type->type_info_table->info[0]->size);
- if( !exception_object )
- throw std::bad_alloc();
- cpp_type_info const * type = exception_type->type_info_table->info[0];
- if( !(type->flags & class_is_simple_type) && type->copy_constructor.normal_copy_constructor )
+ 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<dummy_exception_type *>(exception_object);
- if( type->flags & class_has_virtual_base )
- (dummy_exception_ptr->*(type->copy_constructor.copy_constructor_with_virtual_base))(source_object,exception_object);
+ dummy_exception_type * dummy_exception_ptr = reinterpret_cast<dummy_exception_type *>(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->*(type->copy_constructor.normal_copy_constructor))(source_object);
+ (dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src);
             }
         else
- memmove(exception_object,source_object,type->size);
- return boost::shared_ptr<void>(exception_object,exception_object_deleter(exception_type,run_destructor));
+ memmove(dst,src,ti.size);
+ }
+
+ boost::shared_ptr<void>
+ clone_msvc_exception( void * src, cpp_exception_type const & et )
+ {
+ assert(src!=0);
+ cpp_type_info const & ti=get_cpp_type_info(et);
+ void * dst = malloc(ti.size);
+ if( !dst )
+ throw std::bad_alloc();
+ copy_msvc_exception(dst,src,ti);
+ return boost::shared_ptr<void>(dst,exception_object_deleter(et));
         }
 
     class
@@ -153,14 +169,14 @@
         cloned_exception( cloned_exception const & );
         cloned_exception & operator=( cloned_exception const & );
 
- cpp_exception_type const * exception_type_;
- boost::shared_ptr<void> exception_object_;
+ cpp_exception_type const & et_;
+ boost::shared_ptr<void> exc_;
 
         public:
 
- cloned_exception( void * source_object, cpp_exception_type const * exception_type ):
- exception_type_(exception_type),
- exception_object_(copy_msvc_exception(source_object,exception_type_,true))
+ cloned_exception( void * exc, cpp_exception_type const & et ):
+ et_(et),
+ exc_(clone_msvc_exception(exc,et_))
             {
             }
 
@@ -171,17 +187,19 @@
         boost::exception_detail::clone_base const *
         clone() const
             {
- return new cloned_exception(exception_object_.get(),exception_type_);
+ return new cloned_exception(exc_.get(),et_);
             }
 
         void
         rethrow() const
             {
- boost::shared_ptr<void const> clone=copy_msvc_exception(exception_object_.get(),exception_type_,false);
+ 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<ULONG_PTR>(clone.get());
- args[2]=reinterpret_cast<ULONG_PTR>(exception_type_);
+ args[1]=reinterpret_cast<ULONG_PTR>(dst);
+ args[2]=reinterpret_cast<ULONG_PTR>(&et_);
             RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args);
             }
         };
@@ -198,6 +216,7 @@
     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<EXCEPTION_POINTERS *>(info_);
         EXCEPTION_RECORD * record=info->ExceptionRecord;
@@ -210,7 +229,7 @@
                     {
                     ptr = new cloned_exception(
                             reinterpret_cast<void *>(record->ExceptionInformation[1]),
- reinterpret_cast<cpp_exception_type const *>(record->ExceptionInformation[2]));
+ *reinterpret_cast<cpp_exception_type const *>(record->ExceptionInformation[2]));
                     result = boost::exception_detail::clone_current_exception_result::success;
                     }
                 catch(
@@ -221,7 +240,7 @@
                 catch(
                 ... )
                     {
- BOOST_ASSERT(0);
+ result = boost::exception_detail::clone_current_exception_result::bad_exception;
                     }
             }
         return EXCEPTION_EXECUTE_HANDLER;
@@ -257,271 +276,3 @@
             }
         }
     }
-
-#if 0
-//This is the original Anthony Williams implementation
-#ifndef EXCEPTION_PTR_HPP
-#define EXCEPTION_PTR_HPP
-#include <typeinfo>
-#include "thread_heap_alloc.hpp"
-#include <string.h>
-#include "thread_primitives.hpp"
-#include <excpt.h>
-
-namespace
-boost
- {
- namespace
- exception_detail
- {
- namespace
- win32
- {
- unsigned const exception_maximum_parameters=15;
- unsigned const exception_noncontinuable=1;
-
- 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;
- };
-
- extern "C"
- {
- __declspec(dllimport) void __stdcall RaiseException(unsigned long,unsigned long,unsigned long,ulong_ptr*);
- }
- }
-
- 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 * dest);
- 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;
- void const * type_info; //std::type_info * type_info;
- 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;
- };
-
- class
- msvc_cloned_exception:
- clone_base
- {
- cpp_exception_type const * exception_type;
- void * exception_object;
- bool run_destructor;
-
- void
- copy( void * source_object )
- {
- BOOST_ASSERT(!exception_object);
- exception_object = malloc(exception_type->type_info_table->info[0]->size);
- if( exception_object )
- {
- cpp_type_info const * type = exception_type->type_info_table->info[0];
- if( !(type->flags & class_is_simple_type) && type->copy_constructor.normal_copy_constructor )
- {
- dummy_exception_type * dummy_exception_ptr = reinterpret_cast<dummy_exception_type *>(exception_object);
- if( type->flags & class_has_virtual_base )
- (dummy_exception_ptr->*(type->copy_constructor.copy_constructor_with_virtual_base))(source_object,exception_object);
- else
- (dummy_exception_ptr->*(type->copy_constructor.normal_copy_constructor))(source_object);
- }
- else
- memmove(exception_object,source_object,type->size);
- run_destructor=true;
- }
- }
-
- public:
-
- msvc_cloned_exception( void * source_object, cpp_exception_type const * exception_type_ ):
- exception_type(exception_type_),
- exception_object(0),
- run_destructor(false)
- {
- copy(source_object);
- }
-
- msvc_cloned_exception( msvc_cloned_exception const & other ):
- exception_type(other.exception_type),
- exception_object(0),
- run_destructor(false)
- {
- copy(other.exception_object);
- }
-
- ~msvc_cloned_exception()
- {
- if( exception_object )
- {
- if( run_destructor )
- {
- dummy_exception_type * dummy_exception_ptr=reinterpret_cast<dummy_exception_type *>(exception_object);
- (dummy_exception_ptr->*(exception_type->destructor))();
- }
- free(exception_object);
- }
- }
-
- void
- rethrow()
- {
- msvc_cloned_exception temp(*this);
-
- detail::win32::ulong_ptr args[detail::cpp_exception_parameter_count];
- args[0]=detail::cpp_exception_magic_flag;
- args[1]=reinterpret_cast<detail::win32::ulong_ptr>(temp.exception_object);
- args[2]=reinterpret_cast<detail::win32::ulong_ptr>(temp.exception_type);
-
- temp.run_destructor=false;
-
- detail::win32::RaiseException(detail::cpp_exception_code,detail::win32::exception_noncontinuable,detail::cpp_exception_parameter_count,args);
- }
- };
- }
-
- typedef boost::intrusive_ptr<detail::msvc_cloned_exception> exception_ptr;
-
- namespace
- exception_detail
- {
- extern "C" int * _errno();
-
- bool
- is_cpp_exception( win32::exception_record * 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( exception_ptr * ptr, void * info_ )
- {
- win32::exception_pointers * info=reinterpret_cast<win32::exception_pointers *>(info_);
- win32::exception_record * record=info->ExceptionRecord;
- if( is_cpp_exception(record) )
- {
- if( !record->ExceptionInformation[2] )
- {
-#if _MSC_VER==1310
- unsigned const exception_info_offset=0x74;
-#elif _MSC_VER==1400
- unsigned const exception_info_offset=0x80;
-#endif
- record = *reinterpret_cast<win32::exception_record * *>(reinterpret_cast<char *>(_errno())+exception_info_offset);
- }
- if( is_cpp_exception(record) && record->ExceptionInformation[2] )
- *ptr = detail::heap_new<msvc_cloned_exception>(reinterpret_cast<void *>(record->ExceptionInformation[1]),
- reinterpret_cast<cpp_exception_type const *>(record->ExceptionInformation[2]));
- }
- return EXCEPTION_EXECUTE_HANDLER;
- }
-
- void
- clone_current_exception( exception_ptr * res )
- {
- __try
- {
- throw;
- }
- __except(exception_cloning_filter(res,GetExceptionInformation()))
- {
- }
- }
- }
-
-
- inline
- exception_ptr
- current_exception()
- {
- exception_ptr res;
- clone_current_exception(&res);
- return res;
- }
-
- inline
- void
- rethrow_exception(exception_ptr p)
- {
- if(p)
- p->rethrow();
- else
- throw "no exception stored";
- }
-
- template<class E>
- exception_ptr
- copy_exception(E e)
- {
- try
- {
- throw e;
- }
- catch( ... )
- {
- return current_exception();
- }
- }
- }
-
-#endif
-#endif

Modified: trunk/libs/exception/test/Jamfile.v2
==============================================================================
--- trunk/libs/exception/test/Jamfile.v2 (original)
+++ trunk/libs/exception/test/Jamfile.v2 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
@@ -11,7 +11,7 @@
   : requirements
       <exception-handling>on
       <source>/boost//exception
-# <define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR
+ <define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR
       ;
 
 #to_string

Modified: trunk/libs/exception/test/cloning_test.cpp
==============================================================================
--- trunk/libs/exception/test/cloning_test.cpp (original)
+++ trunk/libs/exception/test/cloning_test.cpp 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
@@ -146,6 +146,10 @@
 #endif
             }
         catch(
+ T & )
+ {
+ }
+ catch(
         ... )
             {
             BOOST_TEST(false);
@@ -216,6 +220,10 @@
 #endif
             }
         catch(
+ T & )
+ {
+ }
+ catch(
         ... )
             {
             BOOST_TEST(false);
@@ -385,6 +393,11 @@
             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 @@
             BOOST_TEST(false);
             }
         catch(
+ derives_std_boost_exception & x )
+ {
+ //Yay! Non-intrusive cloning supported!
+ BOOST_TEST(boost::get_error_info<my_info>(x));
+ if( int const * p=boost::get_error_info<my_info>(x) )
+ BOOST_TEST(*p==42);
+ }
+ catch(
         boost::unknown_exception & x )
             {
             BOOST_TEST(boost::get_error_info<my_info>(x));
@@ -495,6 +516,14 @@
             BOOST_TEST(false);
             }
         catch(
+ derives_boost_exception & x )
+ {
+ //Yay! Non-intrusive cloning supported!
+ BOOST_TEST(boost::get_error_info<my_info>(x));
+ if( int const * p=boost::get_error_info<my_info>(x) )
+ BOOST_TEST(*p==42);
+ }
+ catch(
         boost::unknown_exception & x )
             {
             BOOST_TEST(boost::get_error_info<my_info>(x));

Modified: trunk/libs/exception/test/copy_exception_test.cpp
==============================================================================
--- trunk/libs/exception/test/copy_exception_test.cpp (original)
+++ trunk/libs/exception/test/copy_exception_test.cpp 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
@@ -6,15 +6,37 @@
 #include <boost/exception_ptr.hpp>
 #include <boost/exception/get_error_info.hpp>
 #include <boost/thread.hpp>
+#include <boost/detail/atomic_count.hpp>
 #include <boost/detail/lightweight_test.hpp>
 
 typedef boost::error_info<struct tag_answer,int> 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 @@
 int
 main()
     {
+ BOOST_TEST(++exc_count==1);
     simple_test();
     thread_test();
+ BOOST_TEST(!--exc_count);
     return boost::report_errors();
     }

Modified: trunk/libs/exception/test/unknown_exception_test.cpp
==============================================================================
--- trunk/libs/exception/test/unknown_exception_test.cpp (original)
+++ trunk/libs/exception/test/unknown_exception_test.cpp 2010-09-02 22:03:15 EDT (Thu, 02 Sep 2010)
@@ -62,6 +62,15 @@
                 BOOST_TEST(false);
             }
         catch(
+ boost::exception & x )
+ {
+ //Yay! Non-intrusive cloning supported!
+ if( int const * d=boost::get_error_info<test>(x) )
+ BOOST_TEST( 42==*d );
+ else
+ BOOST_TEST(false);
+ }
+ catch(
         ... )
             {
             BOOST_TEST(false);
@@ -101,6 +110,11 @@
             {
             }
         catch(
+ std::exception & )
+ {
+ //Yay! Non-intrusive cloning supported!
+ }
+ catch(
         ... )
             {
             BOOST_TEST(false);
@@ -114,6 +128,11 @@
             {
             }
         catch(
+ std::exception & )
+ {
+ //Yay! Non-intrusive cloning supported!
+ }
+ catch(
         ... )
             {
             BOOST_TEST(false);


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk