Rcpp Version 1.0.9
exceptions.h
Go to the documentation of this file.
1 
2 // exceptions.h: Rcpp R/C++ interface class library -- exceptions
3 //
4 // Copyright (C) 2010 - 2020 Dirk Eddelbuettel and Romain Francois
5 // Copyright (C) 2021 - 2020 Dirk Eddelbuettel, Romain Francois and IƱaki Ucar
6 //
7 // This file is part of Rcpp.
8 //
9 // Rcpp is free software: you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Rcpp is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21 
22 #ifndef Rcpp__exceptions__h
23 #define Rcpp__exceptions__h
24 
25 #include <Rversion.h>
26 
27 #ifndef RCPP_DEFAULT_INCLUDE_CALL
28 #define RCPP_DEFAULT_INCLUDE_CALL true
29 #endif
30 
31 #define GET_STACKTRACE() R_NilValue
32 
33 namespace Rcpp {
34 
35  // Throwing an exception must be thread-safe to avoid surprises w/ OpenMP.
36  class exception : public std::exception {
37  public:
38  explicit exception(const char* message_, bool include_call = RCPP_DEFAULT_INCLUDE_CALL) : // #nocov start
39  message(message_),
42  }
43  exception(const char* message_, const char*, int, bool include_call = RCPP_DEFAULT_INCLUDE_CALL) :
44  message(message_),
47  }
48  bool include_call() const {
49  return include_call_;
50  }
51  virtual ~exception() throw() {}
52  virtual const char* what() const throw() {
53  return message.c_str(); // #nocov end
54  }
55  inline void copy_stack_trace_to_r() const;
56  private:
57  std::string message;
59  std::vector<std::string> stack;
60  inline void record_stack_trace();
61  };
62 
63  // simple helper
64  static std::string toString(const int i) { // #nocov start
65  std::ostringstream ostr;
66  ostr << i;
67  return ostr.str(); // #nocov end
68  }
69 
70  class no_such_env : public std::exception {
71  public:
72  no_such_env(const std::string& name) throw() :
73  message(std::string("no such environment: '") + name + "'") {};
74  no_such_env(int pos) throw() :
75  message("no environment in given position '" + toString(pos) + "'") {};
76  virtual ~no_such_env() throw() {};
77  virtual const char* what() const throw() { return message.c_str(); };
78  private:
79  std::string message;
80  };
81 
82  class file_io_error : public std::exception {
83  public:
84  file_io_error(const std::string& file) throw() : // #nocov start
85  message(std::string("file io error: '") + file + "'"), file(file) {};
86  file_io_error(int code, const std::string& file) throw() :
87  message("file io error " + toString(code) + ": '" + file + "'"), file(file) {};
88  file_io_error(const std::string& msg, const std::string& file) throw() :
89  message(msg + ": '" + file + "'"), file(file) {};
90  virtual ~file_io_error() throw() {};
91  virtual const char* what() const throw() { return message.c_str(); };
92  std::string filePath() const throw() { return file; }; // #nocov end
93  private:
94  std::string message;
95  std::string file;
96  } ;
97 
98  class file_not_found : public file_io_error { // #nocov start
99  public:
100  file_not_found(const std::string& file) throw() :
101  file_io_error("file not found", file) {} // #nocov end
102  };
103 
104  class file_exists : public file_io_error { // #nocov start
105  public:
106  file_exists(const std::string& file) throw() :
107  file_io_error("file already exists", file) {} // #nocov end
108  };
109 
110  // Variadic / code generated version of the warning and stop functions
111  // can be found within the respective C++11 or C++98 exceptions.h
112  // included below.
113  inline void warning(const std::string& message) { // #nocov start
114  ::Rf_warning("%s", message.c_str());
115  } // #nocov end
116 
117  inline void NORET stop(const std::string& message) { // #nocov start
118  throw Rcpp::exception(message.c_str());
119  } // #nocov end
120 
121 } // namespace Rcpp
122 
123 
124 namespace Rcpp { namespace internal {
125 
126 inline SEXP longjumpSentinel(SEXP token) {
127  SEXP sentinel = PROTECT(Rf_allocVector(VECSXP, 1));
128  SET_VECTOR_ELT(sentinel, 0, token);
129 
130  SEXP sentinelClass = PROTECT(Rf_mkString("Rcpp:longjumpSentinel"));
131  Rf_setAttrib(sentinel, R_ClassSymbol, sentinelClass) ;
132 
133  UNPROTECT(2);
134  return sentinel;
135 }
136 
137 inline bool isLongjumpSentinel(SEXP x) { // #nocov start
138  return
139  Rf_inherits(x, "Rcpp:longjumpSentinel") &&
140  TYPEOF(x) == VECSXP &&
141  Rf_length(x) == 1;
142 }
143 
144 inline SEXP getLongjumpToken(SEXP sentinel) {
145  return VECTOR_ELT(sentinel, 0);
146 }
147 
148 inline void resumeJump(SEXP token) {
149  if (isLongjumpSentinel(token)) {
150  token = getLongjumpToken(token);
151  }
152  ::R_ReleaseObject(token);
153 #if (defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0))
154  ::R_ContinueUnwind(token);
155 #endif // #nocov end
156  Rf_error("Internal error: Rcpp longjump failed to resume");
157 }
158 
159 }} // namespace Rcpp::internal
160 
161 
162 namespace Rcpp {
163 
165  SEXP token;
166  LongjumpException(SEXP token_) : token(token_) {
169  }
170  }
171 };
172 
173 } // namespace Rcpp
174 
175 
176 // Determine whether to use variadic templated RCPP_ADVANCED_EXCEPTION_CLASS,
177 // warning, and stop exception functions or to use the generated argument macro
178 // based on whether the compiler supports c++11 or not.
179 #if __cplusplus >= 201103L
181 #else
183 #endif
184 
185 namespace Rcpp {
186 
187  #define RCPP_EXCEPTION_CLASS(__CLASS__,__WHAT__) \
188  class __CLASS__ : public std::exception{ \
189  public: \
190  __CLASS__( ) throw() : message( std::string(__WHAT__) + "." ){} ; \
191  __CLASS__( const std::string& message ) throw() : \
192  message( std::string(__WHAT__) + ": " + message + "." ){} ; \
193  virtual ~__CLASS__() throw(){} ; \
194  virtual const char* what() const throw() { return message.c_str() ; } \
195  private: \
196  std::string message ; \
197  } ;
198 
199  #define RCPP_SIMPLE_EXCEPTION_CLASS(__CLASS__,__MESSAGE__) \
200  class __CLASS__ : public std::exception{ \
201  public: \
202  __CLASS__() throw() {} ; \
203  virtual ~__CLASS__() throw(){} ; \
204  virtual const char* what() const throw() { return __MESSAGE__ ; } \
205  } ;
206 
207  RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "Not a matrix.") // #nocov start
208  RCPP_SIMPLE_EXCEPTION_CLASS(parse_error, "Parse error.")
209  RCPP_SIMPLE_EXCEPTION_CLASS(not_s4, "Not an S4 object.")
210  RCPP_SIMPLE_EXCEPTION_CLASS(not_reference, "Not an S4 object of a reference class.")
211  RCPP_SIMPLE_EXCEPTION_CLASS(not_initialized, "C++ object not initialized. (Missing default constructor?)")
212  RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "No such field.") // not used internally
213  RCPP_SIMPLE_EXCEPTION_CLASS(no_such_function, "No such function.")
214  RCPP_SIMPLE_EXCEPTION_CLASS(unevaluated_promise, "Promise not yet evaluated.")
215  RCPP_SIMPLE_EXCEPTION_CLASS(embedded_nul_in_string, "Embedded NUL in string.")
216 
217  // Promoted
218  RCPP_EXCEPTION_CLASS(no_such_slot, "No such slot")
219  RCPP_EXCEPTION_CLASS(not_a_closure, "Not a closure")
220 
221  RCPP_EXCEPTION_CLASS(S4_creation_error, "Error creating object of S4 class")
222  RCPP_EXCEPTION_CLASS(reference_creation_error, "Error creating object of reference class") // not used internally
223  RCPP_EXCEPTION_CLASS(no_such_binding, "No such binding")
224  RCPP_EXCEPTION_CLASS(binding_not_found, "Binding not found")
225  RCPP_EXCEPTION_CLASS(binding_is_locked, "Binding is locked")
226  RCPP_EXCEPTION_CLASS(no_such_namespace, "No such namespace")
227  RCPP_EXCEPTION_CLASS(function_not_exported, "Function not exported")
228  RCPP_EXCEPTION_CLASS(eval_error, "Evaluation error")
229 
230  // Promoted
231  RCPP_ADVANCED_EXCEPTION_CLASS(not_compatible, "Not compatible" ) // #nocov end
232  RCPP_ADVANCED_EXCEPTION_CLASS(index_out_of_bounds, "Index is out of bounds")
233 
234  #undef RCPP_SIMPLE_EXCEPTION_CLASS
235  #undef RCPP_EXCEPTION_CLASS
236  #undef RCPP_ADVANCED_EXCEPTION_CLASS
237 
238 
239 namespace internal {
240 
241  inline SEXP nth(SEXP s, int n) { // #nocov start
242  return Rf_length(s) > n ? (n == 0 ? CAR(s) : CAR(Rf_nthcdr(s, n))) : R_NilValue;
243  }
244 
245  // We want the call just prior to the call from Rcpp_eval
246  // This conditional matches
247  // tryCatch(evalq(sys.calls(), .GlobalEnv), error = identity, interrupt = identity)
248  inline bool is_Rcpp_eval_call(SEXP expr) {
249  SEXP sys_calls_symbol = Rf_install("sys.calls");
250  SEXP identity_symbol = Rf_install("identity");
251  Shield<SEXP> identity_fun(Rf_findFun(identity_symbol, R_BaseEnv));
252  SEXP tryCatch_symbol = Rf_install("tryCatch");
253  SEXP evalq_symbol = Rf_install("evalq");
254 
255  return TYPEOF(expr) == LANGSXP &&
256  Rf_length(expr) == 4 &&
257  nth(expr, 0) == tryCatch_symbol &&
258  CAR(nth(expr, 1)) == evalq_symbol &&
259  CAR(nth(nth(expr, 1), 1)) == sys_calls_symbol &&
260  nth(nth(expr, 1), 2) == R_GlobalEnv &&
261  nth(expr, 2) == identity_fun &&
262  nth(expr, 3) == identity_fun;
263  }
264 } // namespace internal
265 
266 } // namespace Rcpp
267 
268 inline SEXP get_last_call(){
269  SEXP sys_calls_symbol = Rf_install("sys.calls");
270 
271  Rcpp::Shield<SEXP> sys_calls_expr(Rf_lang1(sys_calls_symbol));
272  Rcpp::Shield<SEXP> calls(Rcpp_fast_eval(sys_calls_expr, R_GlobalEnv));
273 
274  SEXP cur, prev;
275  prev = cur = calls;
276  while(CDR(cur) != R_NilValue) {
277  SEXP expr = CAR(cur);
278 
280  break;
281  }
282  prev = cur;
283  cur = CDR(cur);
284  }
285  return CAR(prev);
286 }
287 
288 inline SEXP get_exception_classes( const std::string& ex_class) {
289  Rcpp::Shield<SEXP> res( Rf_allocVector( STRSXP, 4 ) );
290 
291  #ifndef RCPP_USING_UTF8_ERROR_STRING
292  SET_STRING_ELT( res, 0, Rf_mkChar( ex_class.c_str() ) ) ;
293  #else
294  SET_STRING_ELT( res, 0, Rf_mkCharLenCE( ex_class.c_str(), ex_class.size(), CE_UTF8 ) );
295  #endif
296  SET_STRING_ELT( res, 1, Rf_mkChar( "C++Error" ) ) ;
297  SET_STRING_ELT( res, 2, Rf_mkChar( "error" ) ) ;
298  SET_STRING_ELT( res, 3, Rf_mkChar( "condition" ) ) ;
299  return res;
300 }
301 
302 inline SEXP make_condition(const std::string& ex_msg, SEXP call, SEXP cppstack, SEXP classes){
303  Rcpp::Shield<SEXP> res( Rf_allocVector( VECSXP, 3 ) ) ;
304  #ifndef RCPP_USING_UTF8_ERROR_STRING
305  SET_VECTOR_ELT( res, 0, Rf_mkString( ex_msg.c_str() ) ) ;
306  #else
307  Rcpp::Shield<SEXP> ex_msg_rstring( Rf_allocVector( STRSXP, 1 ) ) ;
308  SET_STRING_ELT( ex_msg_rstring, 0, Rf_mkCharLenCE( ex_msg.c_str(), ex_msg.size(), CE_UTF8 ) );
309  SET_VECTOR_ELT( res, 0, ex_msg_rstring ) ;
310  #endif
311  SET_VECTOR_ELT( res, 1, call ) ;
312  SET_VECTOR_ELT( res, 2, cppstack ) ;
313 
314  Rcpp::Shield<SEXP> names( Rf_allocVector( STRSXP, 3 ) );
315  SET_STRING_ELT( names, 0, Rf_mkChar( "message" ) ) ;
316  SET_STRING_ELT( names, 1, Rf_mkChar( "call" ) ) ;
317  SET_STRING_ELT( names, 2, Rf_mkChar( "cppstack" ) ) ;
318  Rf_setAttrib( res, R_NamesSymbol, names ) ;
319  Rf_setAttrib( res, R_ClassSymbol, classes ) ;
320  return res ;
321 }
322 
323 template <typename Exception>
324 inline SEXP exception_to_condition_template( const Exception& ex, bool include_call) {
325 #ifndef RCPP_NO_RTTI
326  std::string ex_class = demangle( typeid(ex).name() ) ;
327 #else
328  std::string ex_class = "<not available>";
329 #endif
330  std::string ex_msg = ex.what() ;
331 
332  Rcpp::Shelter<SEXP> shelter;
333  SEXP call, cppstack;
334  if (include_call) {
335  call = shelter(get_last_call());
336  cppstack = shelter(rcpp_get_stack_trace());
337  } else {
338  call = R_NilValue;
339  cppstack = R_NilValue;
340  }
341  SEXP classes = shelter( get_exception_classes(ex_class) );
342  SEXP condition = shelter( make_condition( ex_msg, call, cppstack, classes) );
343  rcpp_set_stack_trace( R_NilValue ) ;
344  return condition ;
345 }
346 
350 }
351 
352 inline SEXP exception_to_r_condition( const std::exception& ex){
354 }
355 
356 inline SEXP string_to_try_error( const std::string& str){
357  using namespace Rcpp;
358 
359  #ifndef RCPP_USING_UTF8_ERROR_STRING
360  Rcpp::Shield<SEXP> txt(Rf_mkString(str.c_str()));
361  Rcpp::Shield<SEXP> simpleErrorExpr(Rf_lang2(::Rf_install("simpleError"), txt));
362  Rcpp::Shield<SEXP> tryError( Rf_mkString( str.c_str() ) );
363  #else
364  Rcpp::Shield<SEXP> tryError( Rf_allocVector( STRSXP, 1 ) ) ;
365  SET_STRING_ELT( tryError, 0, Rf_mkCharLenCE( str.c_str(), str.size(), CE_UTF8 ) );
366  Rcpp::Shield<SEXP> simpleErrorExpr( Rf_lang2(::Rf_install("simpleError"), tryError ));
367  #endif
368 
369  Rcpp::Shield<SEXP> simpleError( Rf_eval(simpleErrorExpr, R_GlobalEnv) );
370  Rf_setAttrib( tryError, R_ClassSymbol, Rf_mkString("try-error") ) ;
371  Rf_setAttrib( tryError, Rf_install( "condition") , simpleError ) ;
372 
373  return tryError; // #nocov end
374 }
375 
376 inline SEXP exception_to_try_error( const std::exception& ex){
377  return string_to_try_error(ex.what());
378 }
379 
380 std::string demangle( const std::string& name) ;
381 #ifndef RCPP_NO_RTTI
382 #define DEMANGLE(__TYPE__) demangle( typeid(__TYPE__).name() ).c_str()
383 #endif
384 
385 
386 inline void forward_exception_to_r(const std::exception& ex){
387  SEXP stop_sym = Rf_install( "stop" ) ;
389  Rcpp::Shield<SEXP> expr( Rf_lang2( stop_sym , condition ) ) ;
390  Rf_eval( expr, R_GlobalEnv ) ;
391 }
392 
394  SEXP stop_sym = Rf_install( "stop" ) ;
396  Rcpp::Shield<SEXP> expr( Rf_lang2( stop_sym , condition ) ) ;
397  Rf_eval( expr, R_GlobalEnv ) ;
398 }
399 
400 
401 #endif
self & field(const char *name_, T Class::*ptr, const char *docstring=0)
Definition: Module_Field.h:68
std::vector< std::string > stack
Definition: exceptions.h:59
void copy_stack_trace_to_r() const
exception(const char *message_, bool include_call=RCPP_DEFAULT_INCLUDE_CALL)
Definition: exceptions.h:38
bool include_call() const
Definition: exceptions.h:48
bool include_call_
Definition: exceptions.h:58
void record_stack_trace()
std::string message
Definition: exceptions.h:57
exception(const char *message_, const char *, int, bool include_call=RCPP_DEFAULT_INCLUDE_CALL)
Definition: exceptions.h:43
virtual const char * what() const
Definition: exceptions.h:52
virtual ~exception()
Definition: exceptions.h:51
file_exists(const std::string &file)
Definition: exceptions.h:106
virtual ~file_io_error()
Definition: exceptions.h:90
std::string file
Definition: exceptions.h:95
virtual const char * what() const
Definition: exceptions.h:91
std::string filePath() const
Definition: exceptions.h:92
std::string message
Definition: exceptions.h:92
file_io_error(const std::string &msg, const std::string &file)
Definition: exceptions.h:88
file_io_error(int code, const std::string &file)
Definition: exceptions.h:86
file_io_error(const std::string &file)
Definition: exceptions.h:84
file_not_found(const std::string &file)
Definition: exceptions.h:100
virtual const char * what() const
Definition: exceptions.h:77
std::string message
Definition: exceptions.h:77
no_such_env(const std::string &name)
Definition: exceptions.h:72
virtual ~no_such_env()
Definition: exceptions.h:76
no_such_env(int pos)
Definition: exceptions.h:74
#define RCPP_ADVANCED_EXCEPTION_CLASS(__CLASS__, __WHAT__)
Definition: exceptions.h:30
void forward_rcpp_exception_to_r(const Rcpp::exception &ex)
Definition: exceptions.h:393
void forward_exception_to_r(const std::exception &ex)
Definition: exceptions.h:386
SEXP exception_to_try_error(const std::exception &ex)
Definition: exceptions.h:376
std::string demangle(const std::string &name)
Definition: routines.h:192
SEXP string_to_try_error(const std::string &str)
Definition: exceptions.h:356
SEXP get_exception_classes(const std::string &ex_class)
Definition: exceptions.h:288
SEXP rcpp_exception_to_r_condition(const Rcpp::exception &ex)
Definition: exceptions.h:347
SEXP make_condition(const std::string &ex_msg, SEXP call, SEXP cppstack, SEXP classes)
Definition: exceptions.h:302
SEXP get_last_call()
Definition: exceptions.h:268
SEXP exception_to_r_condition(const std::exception &ex)
Definition: exceptions.h:352
SEXP exception_to_condition_template(const Exception &ex, bool include_call)
Definition: exceptions.h:324
#define RCPP_DEFAULT_INCLUDE_CALL
Definition: exceptions.h:28
#define NORET
Definition: headers.h:78
bool isLongjumpSentinel(SEXP x)
Definition: exceptions.h:137
SEXP getLongjumpToken(SEXP sentinel)
Definition: exceptions.h:144
void resumeJump(SEXP token)
Definition: exceptions.h:148
bool is_Rcpp_eval_call(SEXP expr)
Definition: exceptions.h:248
SEXP nth(SEXP s, int n)
Definition: exceptions.h:241
SEXP longjumpSentinel(SEXP token)
Definition: exceptions.h:126
Rcpp API.
Definition: algo.h:28
Promise_Impl< PreserveStorage > Promise
Definition: Promise.h:76
Function_Impl< PreserveStorage > Function
Definition: Function.h:122
RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "Not a matrix.") RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field
void message(SEXP s)
Definition: message.h:26
void warning(const char *fmt, Args &&... args)
Definition: exceptions.h:46
LogicalVector in(const VectorBase< RTYPE, NA, T > &x, const VectorBase< RTYPE, RHS_NA, RHS_T > &table)
Definition: unique.h:77
SEXP Rcpp_fast_eval(SEXP expr, SEXP env)
Definition: Rcpp_eval.h:68
static std::string toString(const int i)
Definition: exceptions.h:64
void NORET stop(const char *fmt, Args &&... args)
Definition: exceptions.h:51
bool is(SEXP x)
Definition: is.h:53
No such field RCPP_EXCEPTION_CLASS(reference_creation_error, "Error creating object of reference class") RCPP_ADVANCED_EXCEPTION_CLASS(not_compatible
S4_Impl< PreserveStorage > S4
Definition: S4.h:75
attribute_hidden SEXP rcpp_set_stack_trace(SEXP e)
Definition: routines.h:186
attribute_hidden SEXP rcpp_get_stack_trace()
Definition: routines.h:180
LongjumpException(SEXP token_)
Definition: exceptions.h:166