Rcpp Version 1.0.14
Loading...
Searching...
No Matches
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
33namespace 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
42 }
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
124namespace Rcpp { namespace internal {
125
128 SET_VECTOR_ELT(sentinel, 0, token);
129
130 SEXP sentinelClass = PROTECT(Rf_mkString("Rcpp:longjumpSentinel"));
132
133 UNPROTECT(2);
134 return sentinel;
135}
136
137inline 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
145 return VECTOR_ELT(sentinel, 0);
146}
147
148inline 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
162namespace Rcpp {
163
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
185namespace 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
212 RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "No such field.") // not used internally
216
217 // Promoted
220
222 RCPP_EXCEPTION_CLASS(reference_creation_error, "Error creating object of reference class") // not used internally
225 RCPP_EXCEPTION_CLASS(binding_is_locked, "Binding is locked")
229
230 // Promoted
233
234 #undef RCPP_SIMPLE_EXCEPTION_CLASS
235 #undef RCPP_EXCEPTION_CLASS
236 #undef RCPP_ADVANCED_EXCEPTION_CLASS
237
238
239namespace 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)
249 SEXP sys_calls_symbol = Rf_install("sys.calls");
250 SEXP identity_symbol = Rf_install("identity");
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
268inline 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
288inline 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
302inline 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
323template <typename Exception>
324inline 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
351
352inline SEXP exception_to_r_condition( const std::exception& ex){
354}
355
356inline 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
376inline SEXP exception_to_try_error( const std::exception& ex){
377 return string_to_try_error(ex.what());
378}
379
380std::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
386inline 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)
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
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
virtual const char * what() const
Definition exceptions.h:91
std::string file
Definition exceptions.h:95
std::string filePath() const
Definition exceptions.h:92
std::string message
Definition exceptions.h:94
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
std::string message
Definition exceptions.h:79
no_such_env(const std::string &name)
Definition exceptions.h:72
virtual ~no_such_env()
Definition exceptions.h:76
virtual const char * what() const
Definition exceptions.h:77
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
#define RCPP_EXCEPTION_CLASS(__CLASS__, __WHAT__)
Definition exceptions.h:187
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
#define RCPP_SIMPLE_EXCEPTION_CLASS(__CLASS__, __MESSAGE__)
Definition exceptions.h:199
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:82
bool isLongjumpSentinel(SEXP x)
Definition exceptions.h:137
T as(SEXP x, ::Rcpp::traits::r_type_primitive_tag)
Definition as.h:43
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:78
Function_Impl< PreserveStorage > Function
Definition Function.h:131
void NORET stop(const std::string &message)
Definition exceptions.h:117
void message(SEXP s)
Definition message.h:26
LogicalVector in(const VectorBase< RTYPE, NA, T > &x, const VectorBase< RTYPE, RHS_NA, RHS_T > &table)
Definition unique.h:77
static std::string toString(const int i)
Definition exceptions.h:64
bool is(SEXP x)
Definition is.h:53
T as(SEXP x)
Definition as.h:151
S4_Impl< PreserveStorage > S4
Definition S4.h:77
void warning(const std::string &message)
Definition exceptions.h:113
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