From a029a7f7acb7fe1a9bd30672b23da577af3c1932 Mon Sep 17 00:00:00 2001 From: Matthias Maier Date: Tue, 22 Oct 2013 08:36:27 +0000 Subject: [PATCH] Reorganize the exception handling in exception.h, remove noexcept(false) annotations from the library * Provide an AssertNothrow macro that does behave exactly like Assert, except that if disable_abort_on_exception was called, it merely prints the exception name and continues normally (instead of throwing the exception). * Use AssertNothrow in ~Subscriptor and ~GrowingVectorMemory to avoid an unexpected call to std::terminate in C++11 mode * Remove noexcept(false) from the library because this seriously inconvenients the user git-svn-id: https://svn.dealii.org/trunk@31378 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/include/deal.II/base/exceptions.h | 136 ++++++++++++------- deal.II/include/deal.II/base/function_time.h | 4 - deal.II/include/deal.II/base/subscriptor.h | 10 -- deal.II/source/base/exceptions.cc | 14 +- deal.II/source/base/subscriptor.cc | 8 +- deal.II/source/lac/vector_memory.cc | 4 +- 6 files changed, 101 insertions(+), 75 deletions(-) diff --git a/deal.II/include/deal.II/base/exceptions.h b/deal.II/include/deal.II/base/exceptions.h index ffea72d31a..3ac055a0ac 100644 --- a/deal.II/include/deal.II/base/exceptions.h +++ b/deal.II/include/deal.II/base/exceptions.h @@ -198,41 +198,40 @@ namespace deal_II_exceptions { /** - * Conditionally abort the program. Depending on whether - * disable_abort_on_exception was called, this function either aborts - * the program flow by printing the error message provided by @p exc - * and calling std::abort(), or throws @p exc instead. + * Conditionally abort the program. + * + * Depending on whether disable_abort_on_exception was called, this + * function either aborts the program flow by printing the error + * message provided by @p exc and calling std::abort(), or + * throws @p exc instead (if @p nothrow is set to false). + * + * If the boolean @p nothrow is set to true and + * disable_abort_on_exception was called, the exception type is just + * printed to deallog and program flow continues. This is useful if + * throwing an exception is prohibited (e.g. in a destructor with + * noexcept(true) or throw()). */ - void abort (const ExceptionBase &exc); + void abort (const ExceptionBase &exc, bool nothrow = false); /** - * This routine does the main work for the exception generation - * mechanism used in the Assert macro. - * - * @ref ExceptionBase + * An enum describing how to treat an exception in issue_error */ - template - void issue_error_abort (const char *file, - int line, - const char *function, - const char *cond, - const char *exc_name, - exc e) + enum ExceptionHandling { - // Fill the fields of the exception object - e.set_fields (file, line, function, cond, exc_name); - - dealii::deal_II_exceptions::internals::abort(e); - } + abort_on_exception, + throw_on_exception, + abort_nothrow_on_exception + }; /** * This routine does the main work for the exception generation - * mechanism used in the AssertThrow macro. + * mechanism used in the Assert macro. * * @ref ExceptionBase */ template - void issue_error (const char *file, + void issue_error (ExceptionHandling handling, + const char *file, int line, const char *function, const char *cond, @@ -241,7 +240,18 @@ namespace deal_II_exceptions { // Fill the fields of the exception object e.set_fields (file, line, function, cond, exc_name); - throw e; + + switch(handling) + { + case abort_on_exception: + dealii::deal_II_exceptions::internals::abort(e); + break; + case abort_nothrow_on_exception: + dealii::deal_II_exceptions::internals::abort(e, /*nothrow =*/ true); + break; + case throw_on_exception: + throw e; + } } } /*namespace internals*/ @@ -261,18 +271,45 @@ namespace deal_II_exceptions * @author Wolfgang Bangerth, 1997, 1998, Matthias Maier, 2013 */ #ifdef DEBUG -#define Assert(cond, exc) \ - { \ - if (!(cond)) \ - ::dealii::deal_II_exceptions::internals:: \ - issue_error_abort (__FILE__, \ - __LINE__, \ - __PRETTY_FUNCTION__, #cond, #exc, exc); \ - } +#define Assert(cond, exc) \ +{ \ + if (!(cond)) \ + ::dealii::deal_II_exceptions::internals:: \ + issue_error(::dealii::deal_II_exceptions::internals::abort_on_exception,\ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #exc, exc); \ +} +#else +#define Assert(cond, exc) \ +{} +#endif + + +/** + * A variant of the Assert macro above that exhibits the same + * runtime behaviour as long as disable_abort_on_exception was not called. + * + * However, if disable_abort_on_exception was called, this macro merely + * prints the exception that would be thrown to deallog and continues + * normally without throwing an exception. + * + * See the ExceptionBase class for more information. + * + * @ingroup Exceptions + * @author Wolfgang Bangerth, 1997, 1998, Matthias Maier, 2013 + */ +#ifdef DEBUG +#define AssertNothrow(cond, exc) \ +{ \ + if (!(cond)) \ + ::dealii::deal_II_exceptions::internals:: \ + issue_error( \ + ::dealii::deal_II_exceptions::internals::abort_nothrow_on_exception, \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #exc, exc); \ +} #else -#define Assert(cond, exc) \ - { } +#define AssertNothrow(cond, exc) \ +{} #endif @@ -289,24 +326,21 @@ namespace deal_II_exceptions * @author Wolfgang Bangerth, 1997, 1998, Matthias Maier, 2013 */ #ifdef HAVE_BUILTIN_EXPECT -#define AssertThrow(cond, exc) \ - { \ - if (__builtin_expect(!(cond), false)) \ - ::dealii::deal_II_exceptions::internals:: \ - issue_error (__FILE__, \ - __LINE__, \ - __PRETTY_FUNCTION__, #cond, #exc, exc); \ - } - +#define AssertThrow(cond, exc) \ +{ \ + if (__builtin_expect(!(cond), false)) \ + ::dealii::deal_II_exceptions::internals:: \ + issue_error(::dealii::deal_II_exceptions::internals::throw_on_exception,\ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #exc, exc); \ +} #else /*ifdef HAVE_BUILTIN_EXPECT*/ -#define AssertThrow(cond, exc) \ - { \ - if (!(cond)) \ - ::dealii::deal_II_exceptions::internals:: \ - issue_error (__FILE__, \ - __LINE__, \ - __PRETTY_FUNCTION__, #cond, #exc, exc); \ - } +#define AssertThrow(cond, exc) \ +{ \ + if (!(cond)) \ + ::dealii::deal_II_exceptions::internals:: \ + issue_error(::dealii::deal_II_exceptions::internals::throw_on_exception,\ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #exc, exc); \ +} #endif /*ifdef HAVE_BUILTIN_EXPECT*/ diff --git a/deal.II/include/deal.II/base/function_time.h b/deal.II/include/deal.II/base/function_time.h index 2b17d0f29f..3615f51f73 100644 --- a/deal.II/include/deal.II/base/function_time.h +++ b/deal.II/include/deal.II/base/function_time.h @@ -77,11 +77,7 @@ public: /** * Virtual destructor. */ -#ifdef DEAL_II_USE_CXX11 - virtual ~FunctionTime() noexcept(false); -#else virtual ~FunctionTime(); -#endif /** * Return the value of the time variable/ diff --git a/deal.II/include/deal.II/base/subscriptor.h b/deal.II/include/deal.II/base/subscriptor.h index d546c876e8..44d425865c 100644 --- a/deal.II/include/deal.II/base/subscriptor.h +++ b/deal.II/include/deal.II/base/subscriptor.h @@ -75,17 +75,7 @@ public: * Destructor, asserting that the counter * is zero. */ -#ifdef DEAL_II_USE_CXX11 - // According to the C++11 standard [class.dtor] 3 in combination with - // [except.spec] 14 and [except.spec] 9---as explained in detail in - // [1]---we're guilty of just terminating in case of throwing an - // exception in ~Subscriptor if we do not annotate it with - // "noexcept(false)" - // [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3204.htm - virtual ~Subscriptor() noexcept(false); -#else virtual ~Subscriptor(); -#endif /** * Assignment operator. diff --git a/deal.II/source/base/exceptions.cc b/deal.II/source/base/exceptions.cc index 89350862fc..28638e8501 100644 --- a/deal.II/source/base/exceptions.cc +++ b/deal.II/source/base/exceptions.cc @@ -281,16 +281,26 @@ namespace deal_II_exceptions namespace internals { - void abort (const ExceptionBase &exc) + void abort (const ExceptionBase &exc, bool nothrow /*= false*/) { if (dealii::deal_II_exceptions::abort_on_exception) { - //* Print the error message and bail out: + // Print the error message and bail out: std::cerr << exc.what() << std::endl; std::abort(); } + else if (nothrow) + { + // We are not allowed to throw, and not allowed to abort. + // Just print the exception name to deallog and continue + // normally: + deallog << "Exception: " << e.get_exc_name() << std::endl; + } else { + // We are not allowed to abort, so just throw the error so just + // throw the error so just throw the error so just throw the + // error: throw exc; } } diff --git a/deal.II/source/base/subscriptor.cc b/deal.II/source/base/subscriptor.cc index b9af279a91..bc039582d7 100644 --- a/deal.II/source/base/subscriptor.cc +++ b/deal.II/source/base/subscriptor.cc @@ -57,11 +57,7 @@ Subscriptor::Subscriptor (const Subscriptor &) {} -#ifdef DEAL_II_USE_CXX11 -Subscriptor::~Subscriptor () noexcept(false) -#else Subscriptor::~Subscriptor () -#endif { // check whether there are still // subscriptions to this object. if @@ -109,8 +105,8 @@ Subscriptor::~Subscriptor () if (infostring == "") infostring = ""; - Assert (counter == 0, - ExcInUse (counter, object_info->name(), infostring)); + AssertNothrow (counter == 0, + ExcInUse (counter, object_info->name(), infostring)); } else { diff --git a/deal.II/source/lac/vector_memory.cc b/deal.II/source/lac/vector_memory.cc index 6ada53b04c..34483b9aa9 100644 --- a/deal.II/source/lac/vector_memory.cc +++ b/deal.II/source/lac/vector_memory.cc @@ -108,8 +108,8 @@ GrowingVectorMemory::~GrowingVectorMemory() noexcept(false) GrowingVectorMemory::~GrowingVectorMemory() #endif { - AssertThrow(current_alloc == 0, - StandardExceptions::ExcMemoryLeak(current_alloc)); + AssertNothrow(current_alloc == 0, + StandardExceptions::ExcMemoryLeak(current_alloc)); if (log_statistics) { deallog << "GrowingVectorMemory:Overall allocated vectors: " -- 2.39.5