1919#define Rcpp_api_meat_Rcpp_eval_h
2020
2121#include < Rcpp/Interrupt.h>
22+ #include < Rversion.h>
23+
24+ #if (defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0))
25+ #define R_HAS_UNWIND
26+ #endif
27+
2228
2329namespace Rcpp {
30+ namespace internal {
31+
32+ #ifdef R_HAS_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+ throw LongjumpException (static_cast <SEXP>(data));
43+ }
44+ }
45+
46+ inline SEXP Rcpp_protected_eval (void * eval_data) {
47+ EvalData* data = static_cast <EvalData*>(eval_data);
48+ return ::Rf_eval (data->expr , data->env );
49+ }
50+
51+ // This is used internally instead of Rf_eval() to make evaluation safer
52+ inline SEXP Rcpp_eval_impl (SEXP expr, SEXP env) {
53+ return Rcpp_fast_eval (expr, env);
54+ }
55+
56+ #else // R < 3.5.0
57+
58+ // Fall back to Rf_eval() when the protect-unwind API is unavailable
59+ inline SEXP Rcpp_eval_impl (SEXP expr, SEXP env) {
60+ return ::Rf_eval (expr, env);
61+ }
62+
63+ #endif
64+
65+ } // namespace internal
66+
67+
68+ #ifdef R_HAS_UNWIND
69+
70+ inline SEXP Rcpp_fast_eval (SEXP expr, SEXP env) {
71+ internal::EvalData data (expr, env);
72+ Shield<SEXP> token (::R_MakeUnwindCont ());
73+ return ::R_UnwindProtect (internal::Rcpp_protected_eval, &data,
74+ internal::Rcpp_maybe_throw, token,
75+ token);
76+ }
77+
78+ #else
79+
80+ inline SEXP Rcpp_fast_eval (SEXP expr, SEXP env) {
81+ return Rcpp_eval (expr, env);
82+ }
83+
84+ #endif
85+
2486
2587inline SEXP Rcpp_eval (SEXP expr, SEXP env) {
2688
@@ -39,8 +101,7 @@ inline SEXP Rcpp_eval(SEXP expr, SEXP env) {
39101 SET_TAG (CDDR (call), ::Rf_install (" error" ));
40102 SET_TAG (CDDR (CDR (call)), ::Rf_install (" interrupt" ));
41103
42- // execute the call
43- Shield<SEXP> res (::Rf_eval (call, R_GlobalEnv));
104+ Shield<SEXP> res (internal::Rcpp_eval_impl (call, R_GlobalEnv));
44105
45106 // check for condition results (errors, interrupts)
46107 if (Rf_inherits (res, " condition" )) {
@@ -49,7 +110,7 @@ inline SEXP Rcpp_eval(SEXP expr, SEXP env) {
49110
50111 Shield<SEXP> conditionMessageCall (::Rf_lang2 (::Rf_install (" conditionMessage" ), res));
51112
52- Shield<SEXP> conditionMessage (:: Rf_eval (conditionMessageCall, R_GlobalEnv));
113+ Shield<SEXP> conditionMessage (internal::Rcpp_eval_impl (conditionMessageCall, R_GlobalEnv));
53114 throw eval_error (CHAR (STRING_ELT (conditionMessage, 0 )));
54115 }
55116
0 commit comments