diff --git a/ChangeLog b/ChangeLog index 9b74cc01d..6ab38dd44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2026-03-29 Iñaki Ucar + + * inst/include/Rcpp/api/meat/Rcpp_eval.h: Remove check for non-API + R_UnboundValue, which is never returned anyway from Rf_findFun + * inst/include/Rcpp/Function.h: Use alternative to R_UnboundValue + * inst/include/Rcpp/Promise.h: Idem + * inst/include/Rcpp/Environment.h: Idem + some refactoring + 2026-03-26 Iñaki Ucar * inst/include/Rcpp/internal/r_vector.h: Use dataptr() again to avoid an diff --git a/inst/include/Rcpp/Environment.h b/inst/include/Rcpp/Environment.h index 0f6f79928..7a77eb020 100644 --- a/inst/include/Rcpp/Environment.h +++ b/inst/include/Rcpp/Environment.h @@ -2,7 +2,8 @@ // Environment.h: Rcpp R/C++ interface class library -- access R environments // // Copyright (C) 2009-2013 Dirk Eddelbuettel and Romain François -// Copyright (C) 2014-2026 Dirk Eddelbuettel, Romain François and Kevin Ushey +// Copyright (C) 2014-2025 Dirk Eddelbuettel, Romain François and Kevin Ushey +// Copyright (C) 2026 Dirk Eddelbuettel, Romain François, Kevin Ushey and Iñaki Ucar // // This file is part of Rcpp. // @@ -95,20 +96,8 @@ namespace Rcpp{ * @return a SEXP (possibly R_NilValue) */ SEXP get(const std::string& name) const { - SEXP env = Storage::get__() ; - SEXP nameSym = Rf_install(name.c_str()); -#if R_VERSION < R_Version(4,5,0) - SEXP res = Rf_findVarInFrame( env, nameSym ) ; -#else - SEXP res = R_getVarEx(nameSym, env, FALSE, R_UnboundValue); -#endif - if( res == R_UnboundValue ) return R_NilValue ; - - /* We need to evaluate if it is a promise */ - if( TYPEOF(res) == PROMSXP){ - res = internal::Rcpp_eval_impl( res, env ) ; // #nocov - } - return res ; + Symbol nameSym = Rf_install(name.c_str()); + return get(nameSym); } /** @@ -122,16 +111,12 @@ namespace Rcpp{ SEXP env = Storage::get__() ; #if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVarInFrame( env, name ) ; + if (res == R_UnboundValue) return R_NilValue; + if (TYPEOF(res) == PROMSXP) + res = internal::Rcpp_eval_impl(res, env); #else - SEXP res = R_getVarEx(name, env, FALSE, R_UnboundValue); + SEXP res = R_getVarEx(name, env, FALSE, R_NilValue); #endif - - if( res == R_UnboundValue ) return R_NilValue ; - - /* We need to evaluate if it is a promise */ - if( TYPEOF(res) == PROMSXP){ - res = internal::Rcpp_eval_impl( res, env ) ; - } return res ; } @@ -144,21 +129,8 @@ namespace Rcpp{ * */ SEXP find( const std::string& name) const{ - SEXP env = Storage::get__() ; - SEXP nameSym = Rf_install(name.c_str()); -#if R_VERSION < R_Version(4,5,0) - SEXP res = Rf_findVar( nameSym, env ) ; -#else - SEXP res = R_getVarEx(nameSym, env, TRUE, R_UnboundValue); -#endif - - if( res == R_UnboundValue ) throw binding_not_found(name) ; - - /* We need to evaluate if it is a promise */ - if( TYPEOF(res) == PROMSXP){ - res = internal::Rcpp_eval_impl( res, env ) ; - } - return res ; + Symbol nameSym = Rf_install(name.c_str()); + return find(nameSym); } /** @@ -171,19 +143,13 @@ namespace Rcpp{ SEXP env = Storage::get__() ; #if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVar( name, env ) ; + if (res == R_UnboundValue) throw binding_not_found(name.c_str()); + if (TYPEOF(res) == PROMSXP) + res = internal::Rcpp_eval_impl(res, env); #else - SEXP res = R_getVarEx(name, env, TRUE, R_UnboundValue); + SEXP res = R_getVarEx(name, env, TRUE, NULL); + if (res == NULL) throw binding_not_found(name.c_str()); #endif - if( res == R_UnboundValue ) { - // Pass on the const char* to the RCPP_EXCEPTION_CLASS's - // const std::string& requirement - throw binding_not_found(name.c_str()) ; - } - - /* We need to evaluate if it is a promise */ - if( TYPEOF(res) == PROMSXP){ - res = internal::Rcpp_eval_impl( res, env ) ; - } return res ; } @@ -199,10 +165,11 @@ namespace Rcpp{ SEXP nameSym = Rf_install(name.c_str()); #if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVarInFrame( Storage::get__() , nameSym ) ; + return res != R_UnboundValue; #else - SEXP res = R_getVarEx(nameSym, Storage::get__(), FALSE, R_UnboundValue); + SEXP res = R_getVarEx(nameSym, Storage::get__(), FALSE, NULL); + return res != NULL; #endif - return res != R_UnboundValue ; } /** diff --git a/inst/include/Rcpp/Function.h b/inst/include/Rcpp/Function.h index 783318b39..58f12d7e9 100644 --- a/inst/include/Rcpp/Function.h +++ b/inst/include/Rcpp/Function.h @@ -1,7 +1,8 @@ // Function.h: Rcpp R/C++ interface class library -- functions (also primitives and builtins) // -// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2026 Dirk Eddelbuettel, Romain François and Iñaki Ucar // // This file is part of Rcpp. // @@ -71,12 +72,13 @@ namespace Rcpp{ Function_Impl(const std::string& name, const std::string& ns) { #if R_VERSION < R_Version(4,5,0) Shield env(Rf_findVarInFrame(R_NamespaceRegistry, Rf_install(ns.c_str()))); + if (env == R_UnboundValue) + stop("there is no namespace called \"%s\"", ns); #else - Shield env(R_getVarEx(Rf_install(ns.c_str()), R_NamespaceRegistry, FALSE, R_UnboundValue)); -#endif - if (env == R_UnboundValue) { + Shield env(R_getVarEx(Rf_install(ns.c_str()), R_NamespaceRegistry, FALSE, R_NilValue)); + if (env == R_NilValue) stop("there is no namespace called \"%s\"", ns); - } +#endif get_function(name, env); } diff --git a/inst/include/Rcpp/Promise.h b/inst/include/Rcpp/Promise.h index 8b4096a01..01bec2978 100644 --- a/inst/include/Rcpp/Promise.h +++ b/inst/include/Rcpp/Promise.h @@ -2,7 +2,8 @@ // // Promise.h: Rcpp R/C++ interface class library -- promises (PROMSXP) // -// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain François +// Copyright (C) 2026 Dirk Eddelbuettel, Romain François and Iñaki Ucar // // This file is part of Rcpp. // @@ -48,13 +49,18 @@ namespace Rcpp{ * Return the result of the PRVALUE macro on the promise */ SEXP value() const{ - SEXP val = PRVALUE( Storage::get__() ) ; - if( val == R_UnboundValue ) throw unevaluated_promise() ; - return val ; + if (!was_evaluated()) throw unevaluated_promise(); + return PRVALUE(Storage::get__()); } bool was_evaluated() const { +#if R_VERSION < R_Version(4,6,0) return PRVALUE(Storage::get__()) != R_UnboundValue ; +#else + SEXP env = environment(); + R_BindingType_t bt = R_GetBindingType(Storage::get__(), env); + return bt != R_BindingTypeUnbound; +#endif } /** diff --git a/inst/include/Rcpp/api/meat/Rcpp_eval.h b/inst/include/Rcpp/api/meat/Rcpp_eval.h index 340d2ac7a..6bd75e253 100644 --- a/inst/include/Rcpp/api/meat/Rcpp_eval.h +++ b/inst/include/Rcpp/api/meat/Rcpp_eval.h @@ -1,5 +1,5 @@ // Copyright (C) 2013 - 2025 Romain Francois -// Copyright (C) 2026 Romain Francois and Dirk Eddelbuettel +// Copyright (C) 2026 Romain Francois, Dirk Eddelbuettel and Iñaki Ucar // // This file is part of Rcpp. // @@ -56,10 +56,6 @@ inline SEXP Rcpp_eval(SEXP expr, SEXP env) { // 'identity' function used to capture errors, interrupts Shield identity(Rf_findFun(::Rf_install("identity"), R_BaseNamespace)); - if (identity == R_UnboundValue) { - stop("Failed to find 'base::identity()'"); - } - // define the evalq call -- the actual R evaluation we want to execute Shield evalqCall(Rf_lang3(::Rf_install("evalq"), expr, env));