From 8f970ae672ebe8a53f7cf6b56c50ef4858fea314 Mon Sep 17 00:00:00 2001 From: Giovanni Bussi <giovanni.bussi@gmail.com> Date: Tue, 13 Nov 2018 15:45:41 +0100 Subject: [PATCH] Completed exception mapping. Now every exception thrown within PLUMED is remapped in the wrapper. In particular: - All standard C++ exceptions are remapped to equivalent ones. - PLUMED exceptions and lepton exceptions are remapped to ad hoc classes. - Any other exception derived from std::exception is mapped to std::exception. - Any other exception is rethrown after printing a warning. --- src/core/Makefile | 2 +- src/core/PlumedMain.cpp | 66 +++++++ src/core/PlumedMainInitializer.cpp | 100 +++++++++-- src/wrapper/Plumed.h | 273 ++++++++++++++++++++++++++--- 4 files changed, 396 insertions(+), 45 deletions(-) diff --git a/src/core/Makefile b/src/core/Makefile index a5acc39c8..47b809e16 100644 --- a/src/core/Makefile +++ b/src/core/Makefile @@ -1,4 +1,4 @@ -USE=config tools +USE=config tools lepton # generic makefile include ../maketools/make.module diff --git a/src/core/PlumedMain.cpp b/src/core/PlumedMain.cpp index 4d31ce87d..89275e293 100644 --- a/src/core/PlumedMain.cpp +++ b/src/core/PlumedMain.cpp @@ -40,16 +40,77 @@ #include "tools/OpenMP.h" #include "tools/Tools.h" #include "tools/Stopwatch.h" +#include "lepton/Exception.h" #include "DataFetchingObject.h" #include <cstdlib> #include <cstring> #include <set> #include <unordered_map> +#include <ios> +#include <future> using namespace std; namespace PLMD { +/// Small utility just used in this file to throw arbitrary exceptions +static void testThrow(const char* what) { + auto words=Tools::getWords(what); + plumed_assert(words.size()>0); +#define __PLUMED_THROW_NOMSG(type) if(words[0]==#type) throw type() +#define __PLUMED_THROW_MSG(type) if(words[0]==#type) throw type(what) + __PLUMED_THROW_MSG(PLMD::ExceptionError); + __PLUMED_THROW_MSG(PLMD::ExceptionDebug); + __PLUMED_THROW_MSG(PLMD::Exception); + __PLUMED_THROW_MSG(PLMD::lepton::Exception); + __PLUMED_THROW_NOMSG(std::bad_exception); +#ifdef __PLUMED_LIBCXX11 + __PLUMED_THROW_NOMSG(std::bad_array_new_length); +#endif + __PLUMED_THROW_NOMSG(std::bad_alloc); +#ifdef __PLUMED_LIBCXX11 + __PLUMED_THROW_NOMSG(std::bad_function_call); + __PLUMED_THROW_NOMSG(std::bad_weak_ptr); +#endif + __PLUMED_THROW_NOMSG(std::bad_cast); + __PLUMED_THROW_NOMSG(std::bad_typeid); + __PLUMED_THROW_MSG(std::underflow_error); + __PLUMED_THROW_MSG(std::overflow_error); + __PLUMED_THROW_MSG(std::range_error); + __PLUMED_THROW_MSG(std::runtime_error); + __PLUMED_THROW_MSG(std::out_of_range); + __PLUMED_THROW_MSG(std::length_error); + __PLUMED_THROW_MSG(std::domain_error); + __PLUMED_THROW_MSG(std::invalid_argument); + __PLUMED_THROW_MSG(std::logic_error); + +#ifdef __PLUMED_LIBCXX11 + if(words[0]=="std::system_error") { + plumed_assert(words.size()>2); + int error_code; + Tools::convert(words[2],error_code); + if(words[1]=="std::generic_category") throw std::system_error(error_code,std::generic_category(),what); + if(words[1]=="std::system_category") throw std::system_error(error_code,std::system_category(),what); + if(words[1]=="std::iostream_category") throw std::system_error(error_code,std::iostream_category(),what); + if(words[1]=="std::future_category") throw std::system_error(error_code,std::future_category(),what); + } +#endif + + if(words[0]=="std::ios_base::failure") { +#ifdef __PLUMED_LIBCXX11 + int error_code=0; + if(words.size()>2) Tools::convert(words[2],error_code); + if(words.size()>1 && words[1]=="std::generic_category") throw std::ios_base::failure(what,std::error_code(error_code,std::generic_category())); + if(words.size()>1 && words[1]=="std::system_category") throw std::ios_base::failure(what,std::error_code(error_code,std::system_category())); + if(words.size()>1 && words[1]=="std::iostream_category") throw std::ios_base::failure(what,std::error_code(error_code,std::iostream_category())); + if(words.size()>1 && words[1]=="std::future_category") throw std::ios_base::failure(what,std::error_code(error_code,std::future_category())); +#endif + throw std::ios_base::failure(what); + } + + plumed_error() << "unknown exception" << what; +} + PlumedMain::PlumedMain(): initialized(false), // automatically write on log in destructor @@ -388,6 +449,11 @@ void PlumedMain::cmd(const std::string & word,void*val) { CHECK_NOTNULL(val,word); OpenMP::setNumThreads(*static_cast<unsigned*>(val)); break; + /* ADDED WITH API==6 */ + /* only used for testing */ + case cmd_throw: + CHECK_NOTNULL(val,word); + testThrow((const char*) val); /* STOP API */ case cmd_setMDEngine: CHECK_NOTINIT(initialized,word); diff --git a/src/core/PlumedMainInitializer.cpp b/src/core/PlumedMainInitializer.cpp index 6ce262328..76d8884e9 100644 --- a/src/core/PlumedMainInitializer.cpp +++ b/src/core/PlumedMainInitializer.cpp @@ -22,9 +22,12 @@ #include "PlumedMainInitializer.h" #include "PlumedMain.h" #include "tools/Exception.h" +#include "lepton/Exception.h" #include <cstdlib> #include <cstring> #include <iostream> +#include <system_error> +#include <future> #if defined __PLUMED_HAS_DLOPEN #include <dlfcn.h> #endif @@ -48,21 +51,6 @@ extern "C" void*plumed_plumedmain_create() { } } -#define __PLUMED_CATCH(e,nothrow) \ - catch(PLMD::ExceptionError & e) { \ - nothrow.handler(nothrow.ptr,20200,e.what(),nullptr); \ - } catch(PLMD::ExceptionDebug & e) { \ - nothrow.handler(nothrow.ptr,20100,e.what(),nullptr); \ - } catch(PLMD::Exception & e) { \ - nothrow.handler(nothrow.ptr,20000,e.what(),nullptr); \ - } catch(std::runtime_error & e) { \ - nothrow.handler(nothrow.ptr,10200,e.what(),nullptr); \ - } catch(std::logic_error & e) { \ - nothrow.handler(nothrow.ptr,10100,e.what(),nullptr); \ - } catch(std::exception & e) { \ - nothrow.handler(nothrow.ptr,10000,e.what(),nullptr); \ - } - extern "C" void plumed_plumedmain_cmd(void*plumed,const char*key,const void*val) { plumed_massert(plumed,"trying to use a plumed object which is not initialized"); auto p=static_cast<PLMD::PlumedMain*>(plumed); @@ -76,7 +64,87 @@ extern "C" void plumed_plumedmain_cmd_nothrow(void*plumed,const char*key,const v try { plumed_massert(plumed,"trying to use a plumed object which is not initialized"); static_cast<PLMD::PlumedMain*>(plumed)->cmd(key,val);; - } __PLUMED_CATCH(e,nothrow) + } catch(PLMD::ExceptionError & e) { + nothrow.handler(nothrow.ptr,20200,e.what(),nullptr); + } catch(PLMD::ExceptionDebug & e) { + nothrow.handler(nothrow.ptr,20100,e.what(),nullptr); + } catch(PLMD::Exception & e) { + nothrow.handler(nothrow.ptr,20000,e.what(),nullptr); + } catch(PLMD::lepton::Exception & e) { + nothrow.handler(nothrow.ptr,19900,e.what(),nullptr); + // 11000 to 12000 are "bad exceptions". message will be copied without new allocations + } catch(bad_exception & e) { + nothrow.handler(nothrow.ptr,11500,e.what(),nullptr); +#ifdef __PLUMED_LIBCXX11 + } catch(bad_array_new_length & e) { + nothrow.handler(nothrow.ptr,11410,e.what(),nullptr); +#endif + } catch(bad_alloc & e) { + nothrow.handler(nothrow.ptr,11400,e.what(),nullptr); +#ifdef __PLUMED_LIBCXX11 + } catch(bad_function_call & e) { + nothrow.handler(nothrow.ptr,11300,e.what(),nullptr); + } catch(bad_weak_ptr & e) { + nothrow.handler(nothrow.ptr,11200,e.what(),nullptr); +#endif + } catch(bad_cast & e) { + nothrow.handler(nothrow.ptr,11100,e.what(),nullptr); + } catch(bad_typeid & e) { + nothrow.handler(nothrow.ptr,11000,e.what(),nullptr); + // not implemented yet: std::regex_error + // we do not allow regex yet due to portability problems with gcc 4.8 + // as soon as we transition to using <regex> it should be straightforward to add + } catch(std::ios_base::failure & e) { +#ifdef __PLUMED_LIBCXX11 + int value=e.code().value(); + const void* opt[3]= {"c",&value,nullptr}; // "c" passes the error code. nullptr terminates the optional part. + if(e.code().category()==generic_category()) nothrow.handler(nothrow.ptr,10230,e.what(),opt); + else if(e.code().category()==system_category()) nothrow.handler(nothrow.ptr,10231,e.what(),opt); + else if(e.code().category()==iostream_category()) nothrow.handler(nothrow.ptr,10232,e.what(),opt); + else if(e.code().category()==future_category()) nothrow.handler(nothrow.ptr,10233,e.what(),opt); +#endif + // 10239 represents std::ios_base::failure with default constructur + nothrow.handler(nothrow.ptr,10239,e.what(),nullptr); +#ifdef __PLUMED_LIBCXX11 + } catch(std::system_error & e) { + int value=e.code().value(); + const void* opt[3]= {"c",&value,nullptr}; // "c" passes the error code. nullptr terminates the optional part. + if(e.code().category()==generic_category()) nothrow.handler(nothrow.ptr,10220,e.what(),opt); + else if(e.code().category()==system_category()) nothrow.handler(nothrow.ptr,10221,e.what(),opt); + else if(e.code().category()==iostream_category()) nothrow.handler(nothrow.ptr,10222,e.what(),opt); + else if(e.code().category()==future_category()) nothrow.handler(nothrow.ptr,10223,e.what(),opt); + // fallback to generic runtime_error + else nothrow.handler(nothrow.ptr,10200,e.what(),nullptr); +#endif + } catch(std::underflow_error &e) { + nothrow.handler(nothrow.ptr,10215,e.what(),nullptr); + } catch(std::overflow_error &e) { + nothrow.handler(nothrow.ptr,10210,e.what(),nullptr); + } catch(std::range_error &e) { + nothrow.handler(nothrow.ptr,10205,e.what(),nullptr); + } catch(std::runtime_error & e) { + nothrow.handler(nothrow.ptr,10200,e.what(),nullptr); + // not implemented yet: std::future_error + // not clear how useful it would be. + } catch(std::out_of_range & e) { + nothrow.handler(nothrow.ptr,10120,e.what(),nullptr); + } catch(std::length_error & e) { + nothrow.handler(nothrow.ptr,10115,e.what(),nullptr); + } catch(std::domain_error & e) { + nothrow.handler(nothrow.ptr,10110,e.what(),nullptr); + } catch(std::invalid_argument & e) { + nothrow.handler(nothrow.ptr,10105,e.what(),nullptr); + } catch(std::logic_error & e) { + nothrow.handler(nothrow.ptr,10100,e.what(),nullptr); + // generic exception. message will be copied without new allocations + // reports all non caught exceptions that are derived from std::exception + // for instance, boost exceptions would end up here + } catch(std::exception & e) { + nothrow.handler(nothrow.ptr,10000,e.what(),nullptr); + } catch(...) { + std::cerr<<"+++ rethrowing an unknown error happened while using a plumed cmd"<<std::endl; + throw; + } } extern "C" void plumed_plumedmain_finalize(void*plumed) { diff --git a/src/wrapper/Plumed.h b/src/wrapper/Plumed.h index a3c0cba3b..854315e4a 100644 --- a/src/wrapper/Plumed.h +++ b/src/wrapper/Plumed.h @@ -255,6 +255,40 @@ When you compile the FORTRAN interface, wrapper functions are added with several possible name mangligs, so you should not experience problems linking the plumed library with a FORTRAN file. +\paragraph ReferencePlumedH-exceptions Error handling + + Bad things happen. In case an error is detected by PLUMED, either because of some user error, some internal bug, + or some mistake in using the library, an exception will be thrown. The behavior is different depending if you use + PLUMED from C/FORTRAN or from C++. + + First of all, notice that access to PLUMED goes through three functions: + - plumed_create: this, as of PLUMED 2.5, is guaranteed not to throw any exception. If there is a problem, it will + just return a NULL pointer + - plumed_cmd: this function might throw exceptions. + - plumed_finalize: this is a destructor and is guaranteed not to throw any exception. + + The following discussion concerns all the exceptions thrown by plumed_cmd. + + If you use C/FORTRAN, you will basically have no way to intercept the exception and the program will just terminate. + + If you use C++ but you are calling the C interface (e.g. \ref plumed_cmd), then you might be + able to catch the exceptions thrown by PLUMED. Notice that all the exceptions thrown by PLUMED inherit from std::exception, + so you might want to catch it by reference. Notice however that there is a C layer between your C++ code and the PLUMED + library. In principle, the stack unwinding performed during exception handling is undefined in C and might lead to problems + that are system and compiler dependent. In addition to this, there might be troubles when combining different compilers + or different standard libraries. E.g., if you MD code is linked against a given C++ library and PLUMED is linked against + another one, the two std::exception types will differ and you won't be able to catch exceptions raised by PLUMED. + + If you use C++ and you are calling the C++ interface (e.g. \ref Plumed::cmd), as of PLUMED 2.5 we implemented a complete + remapping of the exceptions thrown by PLUMED. This solves both the problems mentioned above. In particular: + - Instead of throwing an exception, PLUMED will return (using a \ref plumed_nothrow_handler) the details about the occurred error. + - An equivalent exception will be thrown within the inline PLUMED interface compiled with your MD code. + + As a consequence, you will be able to combine different compilers and avoid stack unwinding in the C layer. + + The remapping of exceptions takes care of all the standard C++ exceptions plus all the exceptions raised within + PLUMED. Unexpected exceptions that are derived from std::exception will be rethrown as std::exception. + \paragraph ReferencePlumedH-2-5 New in PLUMED 2.5 The wrappers in PLUMED 2.5 have been completely rewritten with several improvements. @@ -433,6 +467,24 @@ #define __PLUMED_WRAPPER_CXX_DEFAULT_INVALID 0 #endif +/* + Size of a buffer used to store message for exceptions with noexcept constructor. + Should typically hold short messages. Anyway, as long as the stack size stays within the correct + limits it does not seem to affect efficiency. Notice that there cannot be recursive calls of + PLMD::Plumed::cmd, so that it should be in practice irrelevant. +*/ +#ifndef __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER +#define __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER 512 +#endif + + +/* + By default, assume C++11 compliant library is not available. +*/ + +#ifndef __PLUMED_WRAPPER_LIBCXX11 +#define __PLUMED_WRAPPER_LIBCXX11 0 +#endif /* The following macros are just to define shortcuts */ @@ -929,17 +981,22 @@ __PLUMED_WRAPPER_EXTERN_C_END /*}*/ #if defined( __cplusplus) && __PLUMED_WRAPPER_CXX /*{*/ -/* this is to include the NULL pointer */ #if __PLUMED_WRAPPER_CXX_STD -#include <cstdlib> +#include <cstdlib> /* NULL getenv */ +#include <cstring> /* strncat strlen */ #else #include <stdlib.h> +#include <string.h> #endif -/* these are to include standard exceptions */ -#include <exception> -#include <stdexcept> -#include <string> +#include <exception> /* exception */ +#include <stdexcept> /* runtime_error logic_error invalid_argument domain_error length_error out_of_range range_error overflow_error underflow_error */ +#include <string> /* string */ +#include <ios> /* iostream_category (C++11) ios_base::failure (C++11 and C++<11) */ +#if __cplusplus > 199711L +#include <system_error> /* generic_category system_category */ +#include <future> /* future_category */ +#endif /* C++ interface is hidden in PLMD namespace (same as plumed library) */ namespace PLMD { @@ -968,18 +1025,126 @@ class Plumed { */ struct NothrowHandler { + /** code used for translating messages */ int code; + /** short message buffer for non-throwing exceptions */ + char exception_buffer[__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER]; + /** if exception_buffer='\0', message stored as an allocatable string */ ::std::string what; + /** error code for system_error */ + int error_code; }; /** Callback function that sets the error handler. + + opt argument is interpreted as the pointer to a null terminated array of void*. + The number of non-null element is expected to be even, and there should be a null element + that follows. Every pair of pointers should point + to a char, identifying the type of argument passed, and an arbitrary object. + Currently used to (optionally) pass error_code. */ static void nothrow_handler(void*ptr,int code,const char*what,const void* opt) { NothrowHandler* h=(NothrowHandler*) ptr; h->code=code; - h->what=what; - (void) opt; /* not used yet */ + h->exception_buffer[0]='\0'; + h->what.clear(); + h->error_code=0; + /* + These codes correspond to exceptions that should not allocate a separate buffer but use the fixed one. + Notice that a mismatch between the exceptions using the stack buffer here and those implementing + the stack buffer would be in practice harmless. However, it makes sense to be consistent. + */ + if(code==10000 || (code>=11000 && code<12000)) { + __PLUMED_WRAPPER_STD strncat(h->exception_buffer,what,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1); + } else { + h->what=what; + } + + /* interpret optional arguments */ + const void** options=(const void**)opt; + if(options) while(*options) { + if(*((char*)*options)=='c') h->error_code=*((int*)*(options+1)); + options+=2; + } + + static const char* debug=__PLUMED_WRAPPER_STD getenv("PLUMED_EXCEPTIONS_DEBUG"); + + if(debug) { + fprintf(stderr,"+++ PLUMED_EXCEPTIONS_DEBUG\n"); + fprintf(stderr,"+++ code: %d error_code: %d message:\n%s\n",h->code,h->error_code,what); + if(__PLUMED_WRAPPER_STD strlen(what) > __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1) fprintf(stderr,"+++ WARNING: message will be truncated\n"); + fprintf(stderr,"+++ END PLUMED_EXCEPTIONS_DEBUG\n"); + } + + } + + /** + Rethrow the exception. + */ + + static void rethrow(const NothrowHandler&h) { + /* The interpretation of the codes should be kept in sync with core/PlumedMainInitializer.cpp */ + /* check if we are using a full string or a fixes size buffer */ + const char* msg=(h.exception_buffer[0]?h.exception_buffer:h.what.c_str()); + if(h.code==1) throw Plumed::Invalid(msg); + /* logic errors */ + if(h.code>=10100 && h.code<10200) { + if(h.code>=10105 && h.code<10110) throw ::std::invalid_argument(msg); + if(h.code>=10110 && h.code<10115) throw ::std::domain_error(msg); + if(h.code>=10115 && h.code<10120) throw ::std::length_error(msg); + if(h.code>=10120 && h.code<10125) throw ::std::out_of_range(msg); + throw ::std::logic_error(msg); + } + /* runtime errors */ + if(h.code>=10200 && h.code<10300) { + if(h.code>=10205 && h.code<10210) throw ::std::range_error(msg); + if(h.code>=10210 && h.code<10215) throw ::std::overflow_error(msg); + if(h.code>=10215 && h.code<10220) throw ::std::underflow_error(msg); +#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11 + if(h.code==10220) throw ::std::system_error(h.error_code,::std::generic_category(),msg); + if(h.code==10221) throw ::std::system_error(h.error_code,::std::system_category(),msg); + if(h.code==10222) throw ::std::system_error(h.error_code,::std::iostream_category(),msg); + if(h.code==10223) throw ::std::system_error(h.error_code,::std::future_category(),msg); +#endif + if(h.code>=10230 && h.code<10240) { +#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11 +// These cases are probably useless as it looks like this should always be std::iostream_category + if(h.code==10230) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::generic_category())); + if(h.code==10231) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::system_category())); + if(h.code==10232) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::iostream_category())); + if(h.code==10233) throw ::std::ios_base::failure(msg,std::error_code(h.error_code,::std::future_category())); +#endif + throw ::std::ios_base::failure(msg); + } + throw ::std::runtime_error(msg); + } + /* "bad" errors */ + if(h.code>=11000 && h.code<11100) throw Plumed::std_bad_typeid(msg); + if(h.code>=11100 && h.code<11200) throw Plumed::std_bad_cast(msg); +#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11 + if(h.code>=11200 && h.code<11300) throw Plumed::std_bad_weak_ptr(msg); + if(h.code>=11300 && h.code<11400) throw Plumed::std_bad_function_call(msg); +#endif + if(h.code>=11400 && h.code<11500) { +#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11 + if(h.code>=11410 && h.code<11420) throw Plumed::std_bad_array_new_length(msg); +#endif + throw Plumed::std_bad_alloc(msg); + } + if(h.code>=11500 && h.code<11600) throw Plumed::std_bad_exception(msg); + /* lepton error */ + if(h.code>=19900 && h.code<20000) throw Plumed::LeptonException(msg); + /* plumed exceptions */ + if(h.code>=20000 && h.code<30000) { + /* debug - only raised with debug options */ + if(h.code>=20100 && h.code<20200) throw Plumed::ExceptionDebug(msg); + /* error - runtime check */ + if(h.code>=20200 && h.code<20300) throw Plumed::ExceptionError(msg); + throw Plumed::Exception(msg); + } + /* fallback for any other exception */ + throw Plumed::std_exception(msg); } public: @@ -1035,6 +1200,70 @@ public: ~Invalid() __PLUMED_WRAPPER_CXX_NOEXCEPT {} }; + /** + Class used to rethrow Lepton exceptions. + */ + + class LeptonException : + public ::std::exception + { + ::std::string msg; + public: + LeptonException(const char* msg): msg(msg) {} + LeptonException(const LeptonException & other): msg(other.what()) {} + const char* what() const __PLUMED_WRAPPER_CXX_NOEXCEPT {return msg.c_str();} + ~LeptonException() __PLUMED_WRAPPER_CXX_NOEXCEPT {} + }; + +private: + /* + These exceptions are declared as private as they are not supposed to be + catched by value. they only exist to allow a buffer to be attached to + the std::exceptions that do not contain it already. + Notice that these exceptions are those whose constructor should never throw, and as + such they use a fixed size buffer. + */ + +#define __PLUMED_WRAPPER_NOSTRING_EXCEPTION(name) \ + class std_ ## name : \ + public ::std::name \ + { \ + char msg[__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER]; \ + public: \ + std_ ## name(const char * msg) __PLUMED_WRAPPER_CXX_NOEXCEPT { \ + this->msg[0]='\0'; \ + __PLUMED_WRAPPER_STD strncat(this->msg,msg,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1); \ + static const char* debug=__PLUMED_WRAPPER_STD getenv("PLUMED_EXCEPTIONS_DEBUG"); \ + if(debug && __PLUMED_WRAPPER_STD strlen(msg) > __PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1) fprintf(stderr,"+++ WARNING: message will be truncated\n"); \ + } \ + std_ ## name(const std_ ## name & other) __PLUMED_WRAPPER_CXX_NOEXCEPT { \ + msg[0]='\0'; \ + __PLUMED_WRAPPER_STD strncat(msg,other.msg,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1); \ + } \ + std_ ## name & operator=(const std_ ## name & other) __PLUMED_WRAPPER_CXX_NOEXCEPT { \ + if(this==&other) return *this;\ + msg[0]='\0'; \ + __PLUMED_WRAPPER_STD strncat(msg,other.msg,__PLUMED_WRAPPER_CXX_EXCEPTION_BUFFER-1); \ + return *this; \ + } \ + const char* what() const __PLUMED_WRAPPER_CXX_NOEXCEPT {return msg;} \ + ~std_ ## name() __PLUMED_WRAPPER_CXX_NOEXCEPT {} \ + }; + + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_typeid) + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_cast) +#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11 + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_weak_ptr) + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_function_call) +#endif + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_alloc) +#if __cplusplus > 199711L && __PLUMED_WRAPPER_LIBCXX11 + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_array_new_length) +#endif + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(bad_exception) + __PLUMED_WRAPPER_NOSTRING_EXCEPTION(exception) + +public: /** Check if plumed is installed (for runtime binding) @@ -1411,21 +1640,9 @@ Plumed(Plumed&&p)__PLUMED_WRAPPER_CXX_NOEXCEPT : h.code=0; plumed_nothrow_handler nothrow= {&h,nothrow_handler}; plumed_cmd_nothrow(main,key,val,nothrow); - /* The interpretation of the codes should be kept in sync with core/PlumedMainInitializer.cpp */ - if(h.code==0) return; - if(h.code==1) throw Plumed::Invalid(h.what.c_str()); - if(h.code>=10000 && h.code<20000) { - if(h.code>=10100 && h.code<10200) throw ::std::logic_error(h.what.c_str()); - if(h.code>=10200 && h.code<10300) throw ::std::runtime_error(h.what.c_str()); - } - if(h.code>=20000 && h.code<30000) { - if(h.code>=20100 && h.code<20200) throw Plumed::ExceptionDebug(h.what.c_str()); - if(h.code>=20200 && h.code<20300) throw Plumed::ExceptionError(h.what.c_str()); - throw Plumed::Exception(h.what.c_str()); - } - /* all other exception types are mapped to runtime_error */ - throw ::std::runtime_error(h.what.c_str()); + if(h.code!=0) rethrow(h); } + /** Destructor @@ -1600,15 +1817,15 @@ __PLUMED_WRAPPER_ANONYMOUS_END /*}*/ #endif /*}*/ #ifdef __PLUMED_HAS_DLOPEN -#include <dlfcn.h> +#include <dlfcn.h> /* dlopen dlerror dlsym */ #endif #if __PLUMED_WRAPPER_CXX_STD -#include <cstdio> -#include <cstring> -#include <cassert> -#include <cstdlib> -#include <climits> +#include <cstdio> /* fprintf */ +#include <cstring> /* memcpy strlen strncpy memcmp memmove strcmp memcpy */ +#include <cassert> /* assert */ +#include <cstdlib> /* getenv malloc free abort exit */ +#include <climits> /* CHAR_BIT */ #else #include <stdio.h> #include <string.h> -- GitLab