Skip to content

Commit 4f3b17f

Browse files
committed
merge from master
Merge remote-tracking branch 'origin/master' into feature/rcppexports-types Conflicts: ChangeLog
2 parents 8810dd3 + 3e5099c commit 4f3b17f

File tree

5 files changed

+92
-10
lines changed

5 files changed

+92
-10
lines changed

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
* src/attributes.cpp: Include pkg_types.h file in generated
66
C++ interface file if it's present in inst/include or src
77

8+
2015-02-02 JJ Allaire <jj@rstudio.org>
9+
10+
* R/exceptions.R: Evaluate R code within an R_toplevelExec block
11+
* include/Rcpp/api/meat/Rcpp_eval.h: Evaluate R code within an
12+
R_toplevelExec block
13+
814
2015-01-25 Kevin Ushey <kevinushey@gmail.com>
915

1016
* inst/include/Rcpp/utils/tinyformat.h: define an error handler for

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: Rcpp
22
Title: Seamless R and C++ Integration
3-
Version: 0.11.4
4-
Date: 2015-01-20
3+
Version: 0.11.4.1
4+
Date: 2015-02-03
55
Author: Dirk Eddelbuettel, Romain Francois, JJ Allaire, Kevin Ushey,
66
Douglas Bates, and John Chambers
77
Maintainer: Dirk Eddelbuettel <edd@debian.org>

R/exceptions.R

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,18 @@
1919
invisible( .Call( rcpp_error_recorder, e ) )
2020
}
2121

22+
.warningsEnv <- new.env()
23+
.warningsEnv$warnings <- character()
24+
25+
.rcpp_warning_recorder <- function(w){
26+
.warningsEnv$warnings <- append(.warningsEnv$warnings, w$message)
27+
invokeRestart("muffleWarning")
28+
}
29+
30+
.rcpp_collect_warnings <- function() {
31+
warnings <- .warningsEnv$warnings
32+
.warningsEnv$warnings <- character()
33+
warnings
34+
}
35+
36+

inst/NEWS.Rd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
\itemize{
99
\item Defining an error handler for tinyformat prevents \code{assert()}
1010
from spilling.
11+
\item Evaluate R code within an \code{R_toplevelExec} block to prevent
12+
user interrupts from bypassing C++ destructors on the stack.
1113
}
1214
\item Changes in Rcpp Attributes:
1315
\itemize{

inst/include/Rcpp/api/meat/Rcpp_eval.h

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,97 @@
1818
#ifndef Rcpp_api_meat_Rcpp_eval_h
1919
#define Rcpp_api_meat_Rcpp_eval_h
2020

21+
#include <Rcpp/Interrupt.h>
22+
2123
namespace Rcpp{
2224

23-
inline SEXP Rcpp_eval(SEXP expr_, SEXP env) {
24-
Shield<SEXP> expr( expr_) ;
25+
struct EvalCall {
26+
SEXP expr;
27+
SEXP env;
28+
SEXP result;
29+
std::vector<std::string> warnings;
30+
std::string error_message;
31+
};
32+
33+
inline void Rcpp_eval(void* data) {
34+
35+
EvalCall* evalCall = (EvalCall*)data;
36+
SEXP env = evalCall->env;
37+
38+
Shield<SEXP> expr(evalCall->expr) ;
2539

2640
reset_current_error() ;
2741

2842
Environment RCPP = Environment::Rcpp_namespace();
43+
SEXP withCallingHandlersSym = ::Rf_install("withCallingHandlers");
2944
SEXP tryCatchSym = ::Rf_install("tryCatch");
3045
SEXP evalqSym = ::Rf_install("evalq");
3146
SEXP conditionMessageSym = ::Rf_install("conditionMessage");
3247
SEXP errorRecorderSym = ::Rf_install(".rcpp_error_recorder");
48+
SEXP warningRecorderSym = ::Rf_install(".rcpp_warning_recorder");
49+
SEXP collectWarningsSym = ::Rf_install(".rcpp_collect_warnings");
3350
SEXP errorSym = ::Rf_install("error");
51+
SEXP warningSym = ::Rf_install("warning");
3452

35-
Shield<SEXP> call( Rf_lang3(
53+
// define the tryCatchCall
54+
Shield<SEXP> tryCatchCall( Rf_lang3(
3655
tryCatchSym,
3756
Rf_lang3( evalqSym, expr, env ),
3857
errorRecorderSym
3958
) ) ;
40-
SET_TAG( CDDR(call), errorSym ) ;
41-
/* call the tryCatch call */
59+
SET_TAG( CDDR(tryCatchCall), errorSym ) ;
60+
61+
// encose it in withCallingHandlers
62+
Shield<SEXP> call( Rf_lang3(
63+
withCallingHandlersSym,
64+
tryCatchCall,
65+
warningRecorderSym
66+
) ) ;
67+
SET_TAG( CDDR(call), warningSym ) ;
68+
69+
// execute the call
4270
Shield<SEXP> res(::Rf_eval( call, RCPP ) );
4371

72+
// collect warnings
73+
Shield<SEXP> warningCall(Rf_lang1(collectWarningsSym));
74+
Shield<SEXP> warnings(::Rf_eval(warningCall, RCPP));
75+
76+
evalCall->warnings = Rcpp::as<std::vector<std::string> >(warnings);
77+
78+
// check for error
4479
if( error_occured() ) {
4580
Shield<SEXP> current_error ( rcpp_get_current_error() ) ;
4681
Shield<SEXP> conditionMessageCall (::Rf_lang2(conditionMessageSym, current_error)) ;
4782
Shield<SEXP> condition_message (::Rf_eval(conditionMessageCall, R_GlobalEnv)) ;
48-
std::string message(CHAR(::Rf_asChar(condition_message)));
49-
throw eval_error(message) ;
83+
evalCall->error_message = std::string(CHAR(::Rf_asChar(condition_message)));
84+
} else {
85+
evalCall->result = res;
5086
}
87+
}
88+
89+
inline SEXP Rcpp_eval(SEXP expr_, SEXP env) {
5190

52-
return res ;
91+
// create the call object
92+
EvalCall call;
93+
call.expr = expr_;
94+
call.env = env;
95+
96+
// execute it
97+
Rboolean completed = R_ToplevelExec(Rcpp_eval, (void*)&call);
98+
99+
// print warnings
100+
for (size_t i = 0; i<call.warnings.size(); i++)
101+
Rf_warning(call.warnings[i].c_str());
102+
103+
// handle error or result if it completed, else throw interrupt
104+
if (completed) {
105+
if (!call.error_message.empty())
106+
throw eval_error(call.error_message);
107+
else
108+
return call.result;
109+
} else {
110+
throw internal::InterruptedException();
111+
}
53112
}
54113

55114
}

0 commit comments

Comments
 (0)