Skip to content

Commit 1e4e23f

Browse files
committed
handle warnings in Rcpp_eval
1 parent d1a766a commit 1e4e23f

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

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/include/Rcpp/api/meat/Rcpp_eval.h

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,38 +23,57 @@
2323
namespace Rcpp{
2424

2525
struct EvalCall {
26-
SEXP expr_;
26+
SEXP expr;
2727
SEXP env;
2828
SEXP result;
29+
std::vector<std::string> warnings;
2930
std::string error_message;
3031
};
3132

3233
inline void Rcpp_eval(void* data) {
3334

3435
EvalCall* evalCall = (EvalCall*)data;
35-
SEXP expr_ = evalCall->expr_;
3636
SEXP env = evalCall->env;
3737

38-
Shield<SEXP> expr( expr_) ;
38+
Shield<SEXP> expr(evalCall->expr) ;
3939

4040
reset_current_error() ;
4141

4242
Environment RCPP = Environment::Rcpp_namespace();
43+
SEXP withCallingHandlersSym = ::Rf_install("withCallingHandlers");
4344
SEXP tryCatchSym = ::Rf_install("tryCatch");
4445
SEXP evalqSym = ::Rf_install("evalq");
4546
SEXP conditionMessageSym = ::Rf_install("conditionMessage");
4647
SEXP errorRecorderSym = ::Rf_install(".rcpp_error_recorder");
48+
SEXP warningRecorderSym = ::Rf_install(".rcpp_warning_recorder");
49+
SEXP collectWarningsSym = ::Rf_install(".rcpp_collect_warnings");
4750
SEXP errorSym = ::Rf_install("error");
51+
SEXP warningSym = ::Rf_install("warning");
4852

49-
Shield<SEXP> call( Rf_lang3(
53+
// define the tryCatchCall
54+
Shield<SEXP> tryCatchCall( Rf_lang3(
5055
tryCatchSym,
5156
Rf_lang3( evalqSym, expr, env ),
5257
errorRecorderSym
5358
) ) ;
54-
SET_TAG( CDDR(call), errorSym ) ;
55-
/* 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
5670
Shield<SEXP> res(::Rf_eval( call, RCPP ) );
5771

72+
// collect warnings
73+
Shield<SEXP> warnings(::Rf_eval(Rf_lang1(collectWarningsSym), RCPP));
74+
evalCall->warnings = Rcpp::as<std::vector<std::string> >(warnings);
75+
76+
// check for error
5877
if( error_occured() ) {
5978
Shield<SEXP> current_error ( rcpp_get_current_error() ) ;
6079
Shield<SEXP> conditionMessageCall (::Rf_lang2(conditionMessageSym, current_error)) ;
@@ -66,10 +85,21 @@ namespace Rcpp{
6685
}
6786

6887
inline SEXP Rcpp_eval(SEXP expr_, SEXP env) {
88+
89+
// create the call object
6990
EvalCall call;
70-
call.expr_ = expr_;
91+
call.expr = expr_;
7192
call.env = env;
72-
if (R_ToplevelExec(Rcpp_eval, (void*)&call)) {
93+
94+
// execute it
95+
Rboolean completed = R_ToplevelExec(Rcpp_eval, (void*)&call);
96+
97+
// print warnings
98+
for (size_t i = 0; i<call.warnings.size(); i++)
99+
Rf_warning(call.warnings[i].c_str());
100+
101+
// handle error or result if it completed, else throw interrupt
102+
if (completed) {
73103
if (!call.error_message.empty())
74104
throw eval_error(call.error_message);
75105
else

0 commit comments

Comments
 (0)