1919#define Rcpp_api_meat_Rcpp_eval_h
2020
2121#include < Rcpp/Interrupt.h>
22+ #include < Rversion.h>
23+
24+ #if (defined(RCPP_PROTECTED_EVAL) && defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0))
25+ #define RCPP_USE_PROTECT_UNWIND
26+ #endif
27+
2228
2329namespace Rcpp {
30+ namespace internal {
31+
32+ #ifdef RCPP_USE_PROTECT_UNWIND
33+
34+ struct EvalData {
35+ SEXP expr;
36+ SEXP env;
37+ EvalData (SEXP expr_, SEXP env_) : expr(expr_), env(env_) { }
38+ };
39+
40+ inline void Rcpp_maybe_throw (void * data, Rboolean jump) {
41+ if (jump) {
42+ SEXP token = static_cast <SEXP>(data);
43+
44+ // Keep the token protected while unwinding because R code might run
45+ // in C++ destructors. Can't use PROTECT() for this because
46+ // UNPROTECT() might be called in a destructor, for instance if a
47+ // Shield<SEXP> is on the stack.
48+ ::R_PreserveObject (token);
49+
50+ throw LongjumpException (token);
51+ }
52+ }
53+
54+ inline SEXP Rcpp_protected_eval (void * eval_data) {
55+ EvalData* data = static_cast <EvalData*>(eval_data);
56+ return ::Rf_eval (data->expr , data->env );
57+ }
58+
59+ // This is used internally instead of Rf_eval() to make evaluation safer
60+ inline SEXP Rcpp_eval_impl (SEXP expr, SEXP env) {
61+ return Rcpp_fast_eval (expr, env);
62+ }
63+
64+ #else // R < 3.5.0
65+
66+ // Fall back to Rf_eval() when the protect-unwind API is unavailable
67+ inline SEXP Rcpp_eval_impl (SEXP expr, SEXP env) {
68+ return ::Rf_eval (expr, env);
69+ }
70+
71+ #endif
72+
73+ } // namespace internal
74+
75+
76+ #ifdef RCPP_USE_PROTECT_UNWIND
77+
78+ inline SEXP Rcpp_fast_eval (SEXP expr, SEXP env) {
79+ internal::EvalData data (expr, env);
80+ Shield<SEXP> token (::R_MakeUnwindCont ());
81+ return ::R_UnwindProtect (internal::Rcpp_protected_eval, &data,
82+ internal::Rcpp_maybe_throw, token,
83+ token);
84+ }
85+
86+ #else
87+
88+ inline SEXP Rcpp_fast_eval (SEXP expr, SEXP env) {
89+ return Rcpp_eval (expr, env);
90+ }
91+
92+ #endif
93+
2494
2595inline SEXP Rcpp_eval (SEXP expr, SEXP env) {
2696
@@ -39,8 +109,7 @@ inline SEXP Rcpp_eval(SEXP expr, SEXP env) {
39109 SET_TAG (CDDR (call), ::Rf_install (" error" ));
40110 SET_TAG (CDDR (CDR (call)), ::Rf_install (" interrupt" ));
41111
42- // execute the call
43- Shield<SEXP> res (::Rf_eval (call, R_GlobalEnv));
112+ Shield<SEXP> res (internal::Rcpp_eval_impl (call, R_GlobalEnv));
44113
45114 // check for condition results (errors, interrupts)
46115 if (Rf_inherits (res, " condition" )) {
@@ -49,7 +118,7 @@ inline SEXP Rcpp_eval(SEXP expr, SEXP env) {
49118
50119 Shield<SEXP> conditionMessageCall (::Rf_lang2 (::Rf_install (" conditionMessage" ), res));
51120
52- Shield<SEXP> conditionMessage (:: Rf_eval (conditionMessageCall, R_GlobalEnv));
121+ Shield<SEXP> conditionMessage (internal::Rcpp_eval_impl (conditionMessageCall, R_GlobalEnv));
53122 throw eval_error (CHAR (STRING_ELT (conditionMessage, 0 )));
54123 }
55124
0 commit comments