Rcpp Version 0.9.10
exceptions.cpp
Go to the documentation of this file.
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
00002 //
00003 // exceptions.cpp: R/C++ interface class library -- exception handling
00004 //
00005 // Copyright (C) 2009 - 2011 Dirk Eddelbuettel and Romain Francois
00006 //
00007 // This file is part of Rcpp.
00008 //
00009 // Rcpp is free software: you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by
00011 // the Free Software Foundation, either version 2 of the License, or
00012 // (at your option) any later version.
00013 //
00014 // Rcpp is distributed in the hope that it will be useful, but
00015 // WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with Rcpp.  If not, see <http://www.gnu.org/licenses/>.
00021 
00022 #include <Rcpp.h>
00023 
00024 namespace Rcpp{
00025         exception::exception( const char* message_, const char* file, int line) : message(message_){
00026                 rcpp_set_stack_trace( stack_trace(file,line) ) ;
00027         }
00028         exception::~exception() throw(){}
00029 
00030 #define RCPP_EXCEPTION_WHAT(__CLASS__) \
00031 const char* __CLASS__::what() const throw(){ return message.c_str(); }
00032 
00033 RCPP_EXCEPTION_WHAT(exception)
00034 
00035 RCPP_EXCEPTION_WHAT(not_compatible)
00036 RCPP_EXCEPTION_WHAT(S4_creation_error)
00037 RCPP_EXCEPTION_WHAT(reference_creation_error)
00038 RCPP_EXCEPTION_WHAT(no_such_binding)
00039 RCPP_EXCEPTION_WHAT(binding_not_found)
00040 RCPP_EXCEPTION_WHAT(binding_is_locked)
00041 RCPP_EXCEPTION_WHAT(no_such_namespace)
00042 RCPP_EXCEPTION_WHAT(eval_error)
00043 
00044 #undef RCPP_EXCEPTION_WHAT
00045 
00046 #define RCPP_SIMPLE_EXCEPTION_WHAT(__CLASS__,__MESSAGE__)  \
00047 const char* __CLASS__::what() const throw(){ return __MESSAGE__ ; }
00048 
00049 RCPP_SIMPLE_EXCEPTION_WHAT(not_a_matrix, "not a matrix" )
00050 RCPP_SIMPLE_EXCEPTION_WHAT(index_out_of_bounds, "index out of bounds" )
00051 RCPP_SIMPLE_EXCEPTION_WHAT(parse_error, "parse error") 
00052 RCPP_SIMPLE_EXCEPTION_WHAT(not_s4, "not an S4 object" )
00053 RCPP_SIMPLE_EXCEPTION_WHAT(not_reference, "not a reference S4 object" )
00054 RCPP_SIMPLE_EXCEPTION_WHAT(not_initialized, "C++ object not initialized" )
00055 RCPP_SIMPLE_EXCEPTION_WHAT(no_such_slot, "no such slot" )
00056 RCPP_SIMPLE_EXCEPTION_WHAT(no_such_field, "no such field" )
00057 RCPP_SIMPLE_EXCEPTION_WHAT(not_a_closure, "not a closure" )
00058 RCPP_SIMPLE_EXCEPTION_WHAT(no_such_function, "no such function" )
00059 RCPP_SIMPLE_EXCEPTION_WHAT(unevaluated_promise, "promise not yet evaluated" )
00060 
00061 #undef RCPP_SIMPLE_EXCEPTION_WHAT
00062 }
00063 
00064 /* for now, the fancy exception handling is only available in GCC, 
00065    simply because we've not investigated if it is available in other 
00066    compilers */
00067 #ifdef RCPP_HAS_DEMANGLING
00068 #include <typeinfo>
00069 #ifdef IS_EARLIER_THAN_GCC_460
00070 #include <exception_defines.h>
00071 #endif
00072 #include <cxxabi.h>
00073 
00074 std::string demangle( const std::string& name ){
00075         std::string real_class ;
00076         int status =-1 ;
00077         char *dem = 0;
00078         dem = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
00079         if( status == 0 ){
00080                 real_class = dem ;
00081                 free(dem);
00082         } else {
00083                 real_class = name ;
00084         }
00085         return real_class ;
00086 }
00087 
00088 /* much inspired from the __verbose_terminate_handler of the GCC */
00089 void forward_uncaught_exceptions_to_r(){
00090         
00091     std::string exception_class ;
00092     bool has_exception_class = false;
00093     std::string exception_what ;
00094     
00095     // Make sure there was an exception; terminate is also called for an
00096     // attempt to rethrow when there is no suitable exception.
00097     std::type_info *t = abi::__cxa_current_exception_type();
00098     if (t){
00099         has_exception_class = true ;
00100         const char *name = t->name() ;
00101         // now we need to demangle "name"
00102         
00103         {
00104             int status = -1;
00105             char *dem = 0;
00106             dem = abi::__cxa_demangle(name, 0, 0, &status);
00107             if( status == 0){
00108                 exception_class = dem ; /* great we can use the demangled name */
00109                 free(dem);
00110             } else{
00111                 exception_class = name ; /* just using the mangled name */
00112             }
00113         }
00114     }
00115         
00116     // If the exception is derived from std::exception, we can give more
00117     // information.
00118     try {              
00119         __throw_exception_again;
00120     } catch (std::exception &exc) { 
00121         exception_what = exc.what() ;
00122     } catch (...) { 
00123         exception_what = "unrecognized exception" ;
00124     }
00125     
00126     SEXP cppExceptSym = Rf_install("cpp_exception");    // cannot cause a gc() once in symbol table
00127     Rf_eval( 
00128             Rf_lang3( 
00129                 cppExceptSym,
00130                      Rf_mkString(exception_what.c_str()), 
00131                      has_exception_class ? Rf_mkString(exception_class.c_str()) : R_NilValue), 
00132                 R_FindNamespace(Rf_mkString("Rcpp"))
00133              ) ; 
00134 }
00135 void forward_exception_to_r( const std::exception& ex){
00136         std::string exception_class ;
00137     std::string exception_what  = ex.what();
00138         const char *name = typeid(ex).name() ;
00139         // now we need to demangle "name"
00140         {
00141                 int status = -1;
00142                 char *dem = 0;
00143                 dem = abi::__cxa_demangle(name, 0, 0, &status);
00144                 if( status == 0){
00145                         exception_class = dem ; /* great we can use the demangled name */
00146                         free(dem);
00147                 } else{
00148                         exception_class = name ; /* just using the mangled name */
00149                 }
00150         }
00151         SEXP cppExceptSym = Rf_install("cpp_exception"); // cannot cause a gc() once in symbol table
00152         Rf_eval( 
00153             Rf_lang3( 
00154                 cppExceptSym,
00155                      Rf_mkString(exception_what.c_str()), 
00156                      Rf_mkString(exception_class.c_str())
00157                 ), R_FindNamespace(Rf_mkString("Rcpp"))
00158         ) ; 
00159 }
00160 #else
00161 void forward_uncaught_exceptions_to_r(){
00162         SEXP cppExceptSym = Rf_install("cpp_exception"); // cannot cause a gc() once in symbol table
00163         Rf_eval( 
00164             Rf_lang3( 
00165                 cppExceptSym,
00166                      Rf_mkString("exception : we don't know how to get the exception message with your compiler, patches welcome"), 
00167                      R_NilValue), 
00168                 R_FindNamespace(Rf_mkString("Rcpp"))
00169              ) ; 
00170 }
00171 void forward_exception_to_r( const std::exception& ex){
00172         SEXP cppExceptSym = Rf_install("cpp_exception"); // cannot cause a gc() once in symbol table
00173         Rf_eval( 
00174             Rf_lang3( 
00175                 cppExceptSym,
00176                      Rf_mkString(ex.what()), 
00177                      R_NilValue), 
00178                 R_FindNamespace(Rf_mkString("Rcpp"))
00179              ) ; 
00180         
00181 }
00182 std::string demangle( const std::string& name ){
00183         return name ;   
00184 }
00185 #endif
00186 SEXP initUncaughtExceptionHandler(){
00187     /* FIXME: we might want to restore the original handler as the package
00188               gets unloaded */
00189     std::set_terminate(forward_uncaught_exceptions_to_r);
00190     return R_NilValue ;
00191 }
00192 
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Defines