Skip to content

[WIP] Feature improve exception message details (closes #184) #667

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

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,7 +1,114 @@
2017-04-14 James J Balamuta <balamut2@illinois.edu>

* inst/include/Rcpp/exceptions.h: Split off macro generation and
variadic function into two separate headers.
* inst/include/Rcpp/Rcpp/exceptions/cpp98/exceptions.h: Contains
generated RCPP_ADVANCED_EXCEPTION_CLASS macro, stop & warning
* inst/include/Rcpp/Rcpp/exceptions/cpp11/exceptions.h: idem but
for variadic versions
* inst/include/Rcpp/utils/tinyformat.h: Enabled ability to use variadic
tinyformat function.

* inst/include/Rcpp/proxy/SlotProxy.h: Passed slot name to exception
throw.

* inst/include/Rcpp/utils/tinyformat.h: Refreshed tinyformat.h against
May 13, 2016 upstream, retained local mods.

* inst/include/Rcpp/Environment.h: Modified formatting of new exception
messages to be more concise.
* inst/include/Rcpp/exceptions.h: idem
* inst/include/Rcpp/Function.h: idem
* inst/include/Rcpp/Promise.h: idem
* inst/include/Rcpp/String.h: idem
* inst/include/Rcpp/Symbol.h: idem
* inst/include/Rcpp/XPtr.h: idem
* inst/include/Rcpp/as.h: idem
* inst/include/Rcpp/r_cast.h: idem
* inst/include/Rcpp/api/meat/DottedPairImpl.h: idem
* inst/include/Rcpp/internal/export.h: idem
* inst/include/Rcpp/proxy/DottedPairProxy.h: idem
* inst/include/Rcpp/vector/MatrixColumn.h: idem
* inst/include/Rcpp/vector/MatrixRow.h: idem
* inst/include/Rcpp/vector/Vector.h: idem

2017-04-11 Dirk Eddelbuettel <edd@debian.org>

* inst/inst/unitTests/testRcppClass/src/init.c (R_init_testRcppClass): Call
R_registerRoutines() and R_useDynamicSymbols(); also ensure
_rcpp_module_boot_* is registered for each module
* inst/unitTests/testRcppClass/NAMESPACE: Added registration

* inst/unitTests/testRcppClass/DESCRIPTION (Title): Title case

* inst/unitTests/testRcppClass/R/rcpp_hello_world.R (rcpp_hello_world):
Call the renamed C++ function
* inst/unitTests/testRcppClass/src/rcpp_hello_world.cpp (rcpp_hello_world_cpp):
Renamed C++ function to be distinct from R function calling it
* inst/unitTests/testRcppClass/src/rcpp_hello_world.h: Ditto
* inst/unitTests/testRcppClass/man/rcpp_hello_world.Rd: Alias renamed
C++ function

2017-04-09 Dirk Eddelbuettel <edd@debian.org>

* inst/unitTests/testRcppModule/src/init.c (R_init_testRcppModule): Call
R_registerRoutines() and R_useDynamicSymbols(); also ensure
_rcpp_module_boot_* is registered for each module
* inst/unitTests/testRcppModule/NAMESPACE: Added registration

* inst/unitTests/testRcppModule/DESCRIPTION (Title): Title case

* inst/unitTests/testRcppModule/R/rcpp_hello_world.R (rcpp_hello_world):
Call the renamed C++ function
* inst/unitTests/testRcppModule/src/rcpp_hello_world.cpp (rcpp_hello_world_cpp):
Renamed C++ function to be distinct from R function calling it
* inst/unitTests/testRcppModule/src/rcpp_hello_world.h: Ditto
* inst/unitTests/testRcppModule/man/rcpp_hello_world.Rd: Alias renamed
C++ function

* inst/unitTests/testRcppModule/man/Rcpp_modules_examples.Rd: Alias
renamed modules
* inst/unitTests/testRcppModule/tests/modules.R: Call renamed module

2017-04-03 Jim Hester <james.f.hester@gmail.com>

* inst/include/Rcpp/exceptions.h: Added support for throwing
exceptions without call stacks.
* inst/include/Rcpp/macros/macros.h: Idem
* inst/unitTests/cpp/exceptions.cpp: Idem
* inst/unitTests/runit.exceptions.R: Idem

2017-04-10 James J Balamuta <balamut2@illinois.edu>

* inst/include/Rcpp/exceptions.h: Added new exception class generation
macro, reworked existing macros, and removed two exceptions not used.
* inst/include/Rcpp/Environment.h: Improved error handling messages
* inst/include/Rcpp/Function.h: idem
* inst/include/Rcpp/Promise.h: idem
* inst/include/Rcpp/S4.h: idem
* inst/include/Rcpp/String.h: idem
* inst/include/Rcpp/Symbol.h: idem
* inst/include/Rcpp/XPtr.h: idem
* inst/include/Rcpp/as.h: idem
* inst/include/Rcpp/r_cast.h: idem
* inst/include/Rcpp/api/meat/DottedPairImpl.h: idem
* inst/include/Rcpp/internal/export.h: idem
* inst/include/Rcpp/proxy/DottedPairProxy.h: idem
* inst/include/Rcpp/proxy/SlotProxy.h: idem
* inst/include/Rcpp/vector/Matrix.h: idem
* inst/include/Rcpp/vector/MatrixColumn.h: idem
* inst/include/Rcpp/vector/MatrixRow.h: idem
* inst/include/Rcpp/vector/Vector.h: idem

2017-03-28 James J Balamuta <balamut2@illinois.edu>

* inst/vignettes/Rcpp-FAQ.Rnw: Added "Known Issues" section to FAQ

2017-03-25 Dirk Eddelbuettel <edd@debian.org>

* LICENSE: Added
* .Rbuildignore: Do not include LICENSE in package

2017-03-17 Dirk Eddelbuettel <edd@debian.org>

* DESCRIPTION: Release 0.12.10
Expand Down
5 changes: 4 additions & 1 deletion inst/NEWS.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
\itemize{
\item Changes in Rcpp API:
\itemize{
\item ...
\item Error messages are now more informative
(James Balamuta in \ghpr{667} addressing \ghit{184}).
}
\item Changes in Rcpp Documentation:
\itemize{
\item Added a Known Issues section to the Rcpp FAQ vignette
(James Balamuta in \ghpr{661} addressing \ghit{628}, \ghit{563},
\ghit{552}, \ghit{460}, \ghit{419}, and \ghit{251}).
\item Rcpp::exceptions can now be constructed without a call stack (Jim
Hester in \ghpr{663}).
}
}
}
Expand Down
19 changes: 11 additions & 8 deletions inst/include/Rcpp/Environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ namespace Rcpp{
Shield<SEXP> res( Rcpp_eval( Rf_lang2( asEnvironmentSym, x ) ) );
return res ;
} catch( const eval_error& ex){
throw not_compatible( "cannot convert to environment" ) ;
const char* fmt =
"Cannot convert object to an environment: "
"[type:%s; target=ENVSXP].";
throw not_compatible(fmt, Rf_type2char(TYPEOF(x))) ;
}
}

Expand Down Expand Up @@ -115,7 +118,7 @@ namespace Rcpp{
}
return res ;
}

/**
* Get an object from the environment
*
Expand All @@ -126,16 +129,16 @@ namespace Rcpp{
SEXP get(Symbol name) const {
SEXP env = Storage::get__() ;
SEXP res = Rf_findVarInFrame( env, name ) ;

if( res == R_UnboundValue ) return R_NilValue ;

/* We need to evaluate if it is a promise */
if( TYPEOF(res) == PROMSXP){
res = Rf_eval( res, env ) ;
}
return res ;
}


/**
* Get an object from the environment or one of its
Expand All @@ -157,7 +160,7 @@ namespace Rcpp{
}
return res ;
}

/**
* Get an object from the environment or one of its
* parents
Expand All @@ -167,13 +170,13 @@ namespace Rcpp{
SEXP find(Symbol name) const{
SEXP env = Storage::get__() ;
SEXP res = Rf_findVar( name, env ) ;

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 = Rf_eval( res, env ) ;
Expand Down
7 changes: 5 additions & 2 deletions inst/include/Rcpp/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ namespace Rcpp{
Storage::set__(x);
break;
default:
throw not_compatible("cannot convert to function") ;
const char* fmt =
"Cannot convert object to a function:"
"[type=%s; target=CLOSXP, SPECIALSXP, or BUILTINSXP].";
throw not_compatible(fmt, Rf_type2char(TYPEOF(x))) ;
}
}

Expand Down Expand Up @@ -87,7 +90,7 @@ namespace Rcpp{
SEXP environment() const {
SEXP fun = Storage::get__() ;
if( TYPEOF(fun) != CLOSXP ) {
throw not_a_closure() ;
throw not_a_closure(Rf_type2char(TYPEOF(fun))) ;
}
return CLOENV(fun) ;
}
Expand Down
6 changes: 4 additions & 2 deletions inst/include/Rcpp/Promise.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ namespace Rcpp{
RCPP_GENERATE_CTOR_ASSIGN(Promise_Impl)

Promise_Impl( SEXP x){
if( TYPEOF(x) != PROMSXP)
throw not_compatible("not a promise") ;
if( TYPEOF(x) != PROMSXP){
const char* fmt = "Not a promise: [type = %s].";
throw not_compatible(fmt, Rf_type2char(TYPEOF(x))) ;
}
Storage::set__(x) ;
}

Expand Down
12 changes: 7 additions & 5 deletions inst/include/Rcpp/S4.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ namespace Rcpp{
return *this ;
}

/**
* Creates an S4 object of the requested class.
*
* @param klass name of the target S4 class
* @throw not_s4 if klass does not map to a known S4 class
/*!
Creates an S4 object of the requested class.
@param klass name of the target S4 class
@throw S4_creation_error if klass does not map to a known S4 class
*/
S4_Impl( const std::string& klass ){
Shield<SEXP> x( R_do_new_object(R_do_MAKE_CLASS(klass.c_str())) );
Expand All @@ -66,6 +65,9 @@ namespace Rcpp{
*/
bool is( const std::string& clazz) const ;

/*!
@throw not_s4 if x is not an S4 class
*/
void update(SEXP x){
if( ! ::Rf_isS4(x) ) throw not_s4() ;
}
Expand Down
10 changes: 8 additions & 2 deletions inst/include/Rcpp/String.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,14 @@ namespace Rcpp {
data = charsxp;
}

if (::Rf_isString(data) && ::Rf_length(data) != 1)
throw ::Rcpp::not_compatible("expecting a single value");
if (::Rf_isString(data) && ::Rf_length(data) != 1){
const char* fmt =
"Expecting a single string value: [type=%s; extent=%i].";
throw ::Rcpp::not_compatible(fmt,
Rf_type2char(TYPEOF(data)),
::Rf_length(data));

}

valid = true;
buffer_ready = false;
Expand Down
4 changes: 3 additions & 1 deletion inst/include/Rcpp/Symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ namespace Rcpp{
break ;
}
default:
throw not_compatible("cannot convert to symbol (SYMSXP)") ;
const char* fmt =
"Cannot convert object to a symbol (%s -> SYMSXP).";
throw not_compatible(fmt, Rf_type2char(type)) ;
}
}

Expand Down
8 changes: 5 additions & 3 deletions inst/include/Rcpp/XPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ class XPtr :
* @param xp external pointer to wrap
*/
explicit XPtr(SEXP x, SEXP tag = R_NilValue, SEXP prot = R_NilValue) {
if( TYPEOF(x) != EXTPTRSXP )
throw ::Rcpp::not_compatible( "expecting an external pointer" ) ;
if( TYPEOF(x) != EXTPTRSXP ) {
const char* fmt = "Expecting an external pointer: [type=%s].";
throw ::Rcpp::not_compatible(fmt, Rf_type2char(TYPEOF(x)) ) ;
}
Storage::set__(x) ;
R_SetExternalPtrTag( x, tag ) ;
R_SetExternalPtrProtected( x, prot ) ;
Expand Down Expand Up @@ -128,7 +130,7 @@ class XPtr :
inline T* checked_get() const {
T* ptr = get();
if (ptr == NULL)
throw ::Rcpp::exception("external pointer is not valid" ) ;
throw ::Rcpp::exception("External pointer is not valid." ) ;
return ptr;
}

Expand Down
22 changes: 19 additions & 3 deletions inst/include/Rcpp/api/meat/DottedPairImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ namespace Rcpp{
} else {
if( ref.isNULL( ) ) throw index_out_of_bounds() ;

if( static_cast<R_xlen_t>(index) > ::Rf_xlength(ref.get__()) ) throw index_out_of_bounds() ;
if( static_cast<R_xlen_t>(index) > ::Rf_xlength(ref.get__()) ) {
const char* fmt = "Index is out of bounds: [index=%s; extent=%s].";
throw index_out_of_bounds(fmt,
static_cast<R_xlen_t>(index),
::Rf_xlength(ref.get__()) ) ;
}

size_t i=1;
SEXP x = ref.get__() ;
Expand All @@ -70,7 +75,12 @@ namespace Rcpp{
template <typename T>
void DottedPairImpl<CLASS>::replace( const int& index, const T& object ) {
CLASS& ref = static_cast<CLASS&>(*this) ;
if( static_cast<R_xlen_t>(index) >= ::Rf_xlength(ref.get__()) ) throw index_out_of_bounds() ;
if( static_cast<R_xlen_t>(index) >= ::Rf_xlength(ref.get__()) ) {
const char* fmt = "Index is out of bounds: [index=%s; extent=%s].";
throw index_out_of_bounds(fmt,
static_cast<R_xlen_t>(index),
::Rf_xlength(ref.get__()) ) ;
}

Shield<SEXP> x( pairlist( object ) );
SEXP y = ref.get__() ;
Expand All @@ -84,7 +94,13 @@ namespace Rcpp{
template <typename CLASS>
void DottedPairImpl<CLASS>::remove( const size_t& index ) {
CLASS& ref = static_cast<CLASS&>(*this) ;
if( static_cast<R_xlen_t>(index) >= Rf_xlength(ref.get__()) ) throw index_out_of_bounds() ;
if( static_cast<R_xlen_t>(index) >= Rf_xlength(ref.get__()) ) {
const char* fmt = "Index is out of bounds: [index=%s; extent=%s].";
throw index_out_of_bounds(fmt,
static_cast<R_xlen_t>(index),
::Rf_xlength(ref.get__()) ) ;
}

if( index == 0 ){
ref.set__( CDR( ref.get__() ) ) ;
} else{
Expand Down
23 changes: 16 additions & 7 deletions inst/include/Rcpp/as.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ namespace Rcpp {
namespace internal {

template <typename T> T primitive_as(SEXP x) {
if (::Rf_length(x) != 1) throw ::Rcpp::not_compatible("expecting a single value");
if (::Rf_length(x) != 1) {
const char* fmt = "Expecting a single value: [extent=%i].";
throw ::Rcpp::not_compatible(fmt, ::Rf_length(x));
}
const int RTYPE = ::Rcpp::traits::r_sexptype_traits<T>::rtype;
Shield<SEXP> y(r_cast<RTYPE>(x));
typedef typename ::Rcpp::traits::storage_type<RTYPE>::type STORAGE;
Expand All @@ -43,10 +46,14 @@ namespace Rcpp {

inline const char* check_single_string(SEXP x) {
if (TYPEOF(x) == CHARSXP) return CHAR(x);
if (! ::Rf_isString(x))
throw ::Rcpp::not_compatible("expecting a string");
if (Rf_length(x) != 1)
throw ::Rcpp::not_compatible("expecting a single value");
if (! ::Rf_isString(x)) {
const char* fmt = "Expecting a string: [type=%s].";
throw ::Rcpp::not_compatible(fmt, Rf_type2char(TYPEOF(x)));
}
if (Rf_length(x) != 1) {
const char* fmt = "Expecting a single value: [extent=%i].";
throw ::Rcpp::not_compatible(fmt, ::Rf_length(x));
}
return CHAR(STRING_ELT(::Rcpp::r_cast<STRSXP>(x), 0));
}

Expand All @@ -66,10 +73,12 @@ namespace Rcpp {

template <typename T> T as(SEXP x, ::Rcpp::traits::r_type_RcppString_tag) {
if (! ::Rf_isString(x)) {
throw ::Rcpp::not_compatible("expecting a string");
const char* fmt = "Expecting a string: [type=%s].";
throw ::Rcpp::not_compatible(fmt, Rf_type2char(TYPEOF(x)));
}
if (Rf_length(x) != 1) {
throw ::Rcpp::not_compatible("expecting a single value");
const char* fmt = "Expecting a single value: [extent=%i].";
throw ::Rcpp::not_compatible(fmt, ::Rf_length(x));
}
return STRING_ELT(::Rcpp::r_cast<STRSXP>(x), 0);
}
Expand Down
Loading