Skip to content

Commit 7f928e7

Browse files
Enchufa2kevinusheyeddelbuettel
authored
Fix R_UnboundValue NOTE (#1466)
* remove unneeded check using non-API R_UnboundValue * use R_NilValue with R_getVarEx to avoid non-API R_UnboundValue + some refactoring * use R_NilValue instead of non-API R_UnboundValue * use R_BindingTypeUnbound instead of non-API R_UnboundValue * update ChangeLog * only need to check for PROMSXP in the old path * NULL instead of R_NilValue Co-authored-by: Kevin Ushey <kevinushey@gmail.com> * NULL instead of R_NilValue Co-authored-by: Kevin Ushey <kevinushey@gmail.com> * fix missing R_UnboundValue in old path --------- Co-authored-by: Kevin Ushey <kevinushey@gmail.com> Co-authored-by: Dirk Eddelbuettel <edd@debian.org>
1 parent 37a554c commit 7f928e7

File tree

5 files changed

+44
-65
lines changed

5 files changed

+44
-65
lines changed

ChangeLog

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
* inst/examples/OpenMP/OpenMPandInline.r: Idem
1010
* inst/tinytest/test_dispatch.R: Idem
1111

12+
2026-03-29 Iñaki Ucar <iucar@fedoraproject.org>
13+
14+
* inst/include/Rcpp/api/meat/Rcpp_eval.h: Remove check for non-API
15+
R_UnboundValue, which is never returned anyway from Rf_findFun
16+
* inst/include/Rcpp/Function.h: Use alternative to R_UnboundValue
17+
* inst/include/Rcpp/Promise.h: Idem
18+
* inst/include/Rcpp/Environment.h: Idem + some refactoring
19+
1220
2026-03-26 Iñaki Ucar <iucar@fedoraproject.org>
1321

1422
* inst/include/Rcpp/internal/r_vector.h: Use dataptr() again to avoid an

inst/include/Rcpp/Environment.h

Lines changed: 18 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
// Environment.h: Rcpp R/C++ interface class library -- access R environments
33
//
44
// Copyright (C) 2009-2013 Dirk Eddelbuettel and Romain François
5-
// Copyright (C) 2014-2026 Dirk Eddelbuettel, Romain François and Kevin Ushey
5+
// Copyright (C) 2014-2025 Dirk Eddelbuettel, Romain François and Kevin Ushey
6+
// Copyright (C) 2026 Dirk Eddelbuettel, Romain François, Kevin Ushey and Iñaki Ucar
67
//
78
// This file is part of Rcpp.
89
//
@@ -95,20 +96,8 @@ namespace Rcpp{
9596
* @return a SEXP (possibly R_NilValue)
9697
*/
9798
SEXP get(const std::string& name) const {
98-
SEXP env = Storage::get__() ;
99-
SEXP nameSym = Rf_install(name.c_str());
100-
#if R_VERSION < R_Version(4,5,0)
101-
SEXP res = Rf_findVarInFrame( env, nameSym ) ;
102-
#else
103-
SEXP res = R_getVarEx(nameSym, env, FALSE, R_UnboundValue);
104-
#endif
105-
if( res == R_UnboundValue ) return R_NilValue ;
106-
107-
/* We need to evaluate if it is a promise */
108-
if( TYPEOF(res) == PROMSXP){
109-
res = internal::Rcpp_eval_impl( res, env ) ; // #nocov
110-
}
111-
return res ;
99+
Symbol nameSym = Rf_install(name.c_str());
100+
return get(nameSym);
112101
}
113102

114103
/**
@@ -122,16 +111,12 @@ namespace Rcpp{
122111
SEXP env = Storage::get__() ;
123112
#if R_VERSION < R_Version(4,5,0)
124113
SEXP res = Rf_findVarInFrame( env, name ) ;
114+
if (res == R_UnboundValue) return R_NilValue;
115+
if (TYPEOF(res) == PROMSXP)
116+
res = internal::Rcpp_eval_impl(res, env);
125117
#else
126-
SEXP res = R_getVarEx(name, env, FALSE, R_UnboundValue);
118+
SEXP res = R_getVarEx(name, env, FALSE, R_NilValue);
127119
#endif
128-
129-
if( res == R_UnboundValue ) return R_NilValue ;
130-
131-
/* We need to evaluate if it is a promise */
132-
if( TYPEOF(res) == PROMSXP){
133-
res = internal::Rcpp_eval_impl( res, env ) ;
134-
}
135120
return res ;
136121
}
137122

@@ -144,21 +129,8 @@ namespace Rcpp{
144129
*
145130
*/
146131
SEXP find( const std::string& name) const{
147-
SEXP env = Storage::get__() ;
148-
SEXP nameSym = Rf_install(name.c_str());
149-
#if R_VERSION < R_Version(4,5,0)
150-
SEXP res = Rf_findVar( nameSym, env ) ;
151-
#else
152-
SEXP res = R_getVarEx(nameSym, env, TRUE, R_UnboundValue);
153-
#endif
154-
155-
if( res == R_UnboundValue ) throw binding_not_found(name) ;
156-
157-
/* We need to evaluate if it is a promise */
158-
if( TYPEOF(res) == PROMSXP){
159-
res = internal::Rcpp_eval_impl( res, env ) ;
160-
}
161-
return res ;
132+
Symbol nameSym = Rf_install(name.c_str());
133+
return find(nameSym);
162134
}
163135

164136
/**
@@ -171,19 +143,13 @@ namespace Rcpp{
171143
SEXP env = Storage::get__() ;
172144
#if R_VERSION < R_Version(4,5,0)
173145
SEXP res = Rf_findVar( name, env ) ;
146+
if (res == R_UnboundValue) throw binding_not_found(name.c_str());
147+
if (TYPEOF(res) == PROMSXP)
148+
res = internal::Rcpp_eval_impl(res, env);
174149
#else
175-
SEXP res = R_getVarEx(name, env, TRUE, R_UnboundValue);
150+
SEXP res = R_getVarEx(name, env, TRUE, NULL);
151+
if (res == NULL) throw binding_not_found(name.c_str());
176152
#endif
177-
if( res == R_UnboundValue ) {
178-
// Pass on the const char* to the RCPP_EXCEPTION_CLASS's
179-
// const std::string& requirement
180-
throw binding_not_found(name.c_str()) ;
181-
}
182-
183-
/* We need to evaluate if it is a promise */
184-
if( TYPEOF(res) == PROMSXP){
185-
res = internal::Rcpp_eval_impl( res, env ) ;
186-
}
187153
return res ;
188154
}
189155

@@ -199,10 +165,11 @@ namespace Rcpp{
199165
SEXP nameSym = Rf_install(name.c_str());
200166
#if R_VERSION < R_Version(4,5,0)
201167
SEXP res = Rf_findVarInFrame( Storage::get__() , nameSym ) ;
168+
return res != R_UnboundValue;
202169
#else
203-
SEXP res = R_getVarEx(nameSym, Storage::get__(), FALSE, R_UnboundValue);
170+
SEXP res = R_getVarEx(nameSym, Storage::get__(), FALSE, NULL);
171+
return res != NULL;
204172
#endif
205-
return res != R_UnboundValue ;
206173
}
207174

208175
/**

inst/include/Rcpp/Function.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11

22
// Function.h: Rcpp R/C++ interface class library -- functions (also primitives and builtins)
33
//
4-
// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois
4+
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
5+
// Copyright (C) 2026 Dirk Eddelbuettel, Romain François and Iñaki Ucar
56
//
67
// This file is part of Rcpp.
78
//
@@ -71,12 +72,13 @@ namespace Rcpp{
7172
Function_Impl(const std::string& name, const std::string& ns) {
7273
#if R_VERSION < R_Version(4,5,0)
7374
Shield<SEXP> env(Rf_findVarInFrame(R_NamespaceRegistry, Rf_install(ns.c_str())));
75+
if (env == R_UnboundValue)
76+
stop("there is no namespace called \"%s\"", ns);
7477
#else
75-
Shield<SEXP> env(R_getVarEx(Rf_install(ns.c_str()), R_NamespaceRegistry, FALSE, R_UnboundValue));
76-
#endif
77-
if (env == R_UnboundValue) {
78+
Shield<SEXP> env(R_getVarEx(Rf_install(ns.c_str()), R_NamespaceRegistry, FALSE, R_NilValue));
79+
if (env == R_NilValue)
7880
stop("there is no namespace called \"%s\"", ns);
79-
}
81+
#endif
8082
get_function(name, env);
8183
}
8284

inst/include/Rcpp/Promise.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
//
33
// Promise.h: Rcpp R/C++ interface class library -- promises (PROMSXP)
44
//
5-
// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois
5+
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain François
6+
// Copyright (C) 2026 Dirk Eddelbuettel, Romain François and Iñaki Ucar
67
//
78
// This file is part of Rcpp.
89
//
@@ -48,13 +49,18 @@ namespace Rcpp{
4849
* Return the result of the PRVALUE macro on the promise
4950
*/
5051
SEXP value() const{
51-
SEXP val = PRVALUE( Storage::get__() ) ;
52-
if( val == R_UnboundValue ) throw unevaluated_promise() ;
53-
return val ;
52+
if (!was_evaluated()) throw unevaluated_promise();
53+
return PRVALUE(Storage::get__());
5454
}
5555

5656
bool was_evaluated() const {
57+
#if R_VERSION < R_Version(4,6,0)
5758
return PRVALUE(Storage::get__()) != R_UnboundValue ;
59+
#else
60+
SEXP env = environment();
61+
R_BindingType_t bt = R_GetBindingType(Storage::get__(), env);
62+
return bt != R_BindingTypeUnbound;
63+
#endif
5864
}
5965

6066
/**

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (C) 2013 - 2025 Romain Francois
2-
// Copyright (C) 2026 Romain Francois and Dirk Eddelbuettel
2+
// Copyright (C) 2026 Romain Francois, Dirk Eddelbuettel and Iñaki Ucar
33
//
44
// This file is part of Rcpp.
55
//
@@ -56,10 +56,6 @@ inline SEXP Rcpp_eval(SEXP expr, SEXP env) {
5656
// 'identity' function used to capture errors, interrupts
5757
Shield<SEXP> identity(Rf_findFun(::Rf_install("identity"), R_BaseNamespace));
5858

59-
if (identity == R_UnboundValue) {
60-
stop("Failed to find 'base::identity()'");
61-
}
62-
6359
// define the evalq call -- the actual R evaluation we want to execute
6460
Shield<SEXP> evalqCall(Rf_lang3(::Rf_install("evalq"), expr, env));
6561

0 commit comments

Comments
 (0)