-
-
Notifications
You must be signed in to change notification settings - Fork 213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider masking definition of Rf_error()? #1247
Comments
Tough. It is a clear issue, and one that is a little tricky to explain / document. I am little burned out from the recent transition dances for Rcpp, BH, and the still-ongoing one for RcppArmadillo. But if you want to drive a test across 2600 reverse depends, and then tangle with all packages that still call Is it worth it? Dunno. Should we maybe consider implementing |
I will try to revisit this issue after the release, given that I got the (long-running) RcppArmadillo transition out of the way. |
About this one, any issue with just defining... #define Rf_error Rcpp::stop in the proper place? |
Yes, though I feel uneasy about only / directly renaming. Maybe via a wrapper that issues something like a deprecation warning? And/or what @kevinushey initially suggested and dieing in error? Other ideas? |
The problem with the initial proposal is that 1) if many packages use this, they will be broken after adding it (admiteddly, they are buggy now, but still we may want to avoid general breakeage), and 2) it doesn't seem to work with Otherwise, in favor of adding a warning via a wrapper on top of renaming. |
I am scrathing my head about a wrapper as these appear to be functions defined in the R header files. The best / only idea I have is to mask that with a |
Yes, with a wrapper I meant something like: #define Rf_error Rcpp::internal::stop_wrapper where |
Still an ugly-ish define but probably the best we can do. |
This may be a draft implementation. Wording to be refined Pending diffHead: feature/mask_error Variadic templates refinement (#1336)
Tag: 1.0.13 (14)
Unstaged changes (1)
modified inst/include/RcppCommon.h
@@ -188,4 +188,6 @@ namespace Rcpp {
#include <Rcpp/internal/wrap.h>
+#include <Rcpp/internal/stop_wrapper.h>
+
#endif
Staged changes (1)
new file inst/include/Rcpp/internal/stop_wrapper.h
@@ -0,0 +1,16 @@
+
+#ifndef RCPP_INTERNAL_STOP_WRAPPER_H
+#define RCPP_INTERNAL_STOP_WRAPPER_H
+
+namespace Rcpp {
+ namespace internal {
+ inline void stop_wrapper(const char *txt) {
+ Rcpp::warning("(Do not call Rf_error directly, rather call Rcpp::stop");
+ Rcpp::stop(txt);
+ }
+ }
+}
+
+#define Rf_error ::Rcpp::internal::stop_wrapper
+
+#endif Demo (using @kevinushey's stub from above, unchanged) -- Code#include <Rcpp.h>
using namespace Rcpp;
struct A {
A() { Rprintf("A()\n"); }
~A() { Rprintf("~A()\n"); }
};
// [[Rcpp::export]]
SEXP uhoh() {
A a;
Rf_error("Oops!");
}
/*** R
uhoh()
*/
Resultedd@rob:~/git/rcpp(feature/mask_error)$ Rscript -e 'Rcpp::sourceCpp("/tmp/r/rcpperror.cpp")'
> uhoh()
A()
~A()
Error in eval(ei, envir) : Oops!
Calls: <Anonymous> ... source -> withVisible -> eval -> eval -> uhoh -> .Call
In addition: Warning message:
In uhoh() : (Do not call Rf_error directly, rather call Rcpp::stop
Execution halted
edd@rob:~/git/rcpp(feature/mask_error)$
Misses a closing paren in the warning text which I'll add. |
Mmmh, on second thought, the problem with this approach is that we are bugging the user instead of the developer. It should be a compilation warning instead of a runtime one. What about #define Rf_error _Pragma("GCC warning \"Invalid use of Rf_error, use Rcpp::stop instead\"") \
Rcpp::stop And it GCC:
Clang:
|
I like that better too. Let'ss see in a rev.dep how many existing CRAN packages we have to write PRs for. |
Please note that there's a test file that requires an diff --git a/inst/include/RcppCommon.h b/inst/include/RcppCommon.h
index 5cbe895b..9d032a63 100644
--- a/inst/include/RcppCommon.h
+++ b/inst/include/RcppCommon.h
@@ -188,4 +188,7 @@ namespace Rcpp {
#include <Rcpp/internal/wrap.h>
+#define Rf_error _Pragma("GCC warning \"Invalid use of Rf_error, use Rcpp::stop instead\"") \
+ Rcpp::stop
+
#endif
diff --git a/inst/tinytest/cpp/stack.cpp b/inst/tinytest/cpp/stack.cpp
index c3fa4178..ec9a7469 100644
--- a/inst/tinytest/cpp/stack.cpp
+++ b/inst/tinytest/cpp/stack.cpp
@@ -23,6 +23,7 @@
#include <Rcpp.h>
using namespace Rcpp;
+#undef Rf_error
// Class that indicates to R caller whether C++ stack was unwound
struct unwindIndicator { |
It's generally better form to protect any (We probably also want a reference to an entry in the Rcpp FAQ and/or an issue ticket with some context and explanation in the message text.) |
I can add the
:) EDIT: Even K&R state that! |
Good find. I prefer explicit code hygiene, if in doubt. But now that you mention it I see such 'naked' #undef in R's code too (src/main/*.c) so I rest my case. I may still wrap mine -- it just seems clearer on intent. |
Nice -- I very much like the idea of using a pragma here. Including a warning could also have other unexpected side effects (e.g. if the function calling Is it worth considering a way for users to opt-out, in case they really do need to use |
|
We can also have the definition itself inside an |
Somewhat related to a recent post on R-devel, some users will still try to use
Rf_error()
in C++ code using Rcpp. However, (as is documented) C++ destructors won't run when a longjmp occurs in cases like this. For example:In this example,
~A()
is never printed.We could consider masking the definition of
Rf_error()
in these contexts. For example, something like:There might also be a way to provide our own definition of
Rf_error()
that "masks" the version provided by R, but I wasn't able to find something immediately obvious.The text was updated successfully, but these errors were encountered: