diff --git a/ChangeLog b/ChangeLog index 9911a8173..fa258238a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,9 +8,18 @@ * inst/include/Rcpp/hash/SelfHash.h: Idem * inst/tinytest/test_sugar.R: Add test for signed zeroes +2025-10-28 Iñaki Ucar + + * inst/include/Rcpp/macros/mask.h: Mask Rf_error with Rcpp::stop with + a warning at compilation time, unless RCPP_NO_MASK_RF_ERROR is defined + * inst/include/RcppCommon.h: Include the previous file in the last place + * src/attributes.cpp: Use parentheses to protect call to Rf_error + * inst/tinytest/cpp/stack.cpp: Idem + * inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp: Idem + 2025-10-21 Iñaki Ucar - * inst/include/Rcpp/exceptions_impl.h: use __has_include to simplify checks + * inst/include/Rcpp/exceptions_impl.h: Use __has_include to simplify checks to enable demangling, making them robust for more platforms 2025-10-13 Dirk Eddelbuettel diff --git a/inst/include/Rcpp/macros/mask.h b/inst/include/Rcpp/macros/mask.h new file mode 100644 index 000000000..a1ff50df2 --- /dev/null +++ b/inst/include/Rcpp/macros/mask.h @@ -0,0 +1,31 @@ +// mask.h: Rcpp R/C++ interface class library -- masking macros +// +// Copyright (C) 2025 Iñaki Ucar +// +// This file is part of Rcpp. +// +// Rcpp is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Rcpp is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Rcpp. If not, see . + +#ifndef Rcpp_macros_mask_h +#define Rcpp_macros_mask_h + +#ifndef RCPP_NO_MASK_RF_ERROR +#define Rf_error(...) \ + _Pragma("GCC warning \"Use of Rf_error() replaced with Rcpp::stop(). Calls \ +to Rf_error() in C++ contexts are unsafe: consider using Rcpp::stop() instead, \ +or define RCPP_NO_MASK_RF_ERROR if this is a false positive.\"") \ + Rcpp::stop(__VA_ARGS__) +#endif + +#endif diff --git a/inst/include/RcppCommon.h b/inst/include/RcppCommon.h index 8f28fd035..1c58e2531 100644 --- a/inst/include/RcppCommon.h +++ b/inst/include/RcppCommon.h @@ -4,7 +4,7 @@ // // Copyright (C) 2008 - 2009 Dirk Eddelbuettel // Copyright (C) 2009 - 2020 Dirk Eddelbuettel and Romain Francois -// Copyright (C) 2021 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar +// Copyright (C) 2021 - 2025 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -191,4 +191,6 @@ namespace Rcpp { #include +#include + #endif diff --git a/inst/tinytest/cpp/stack.cpp b/inst/tinytest/cpp/stack.cpp index c3fa41789..8bb7d52df 100644 --- a/inst/tinytest/cpp/stack.cpp +++ b/inst/tinytest/cpp/stack.cpp @@ -2,7 +2,8 @@ // // misc.cpp: Rcpp R/C++ interface class library -- misc unit tests // -// Copyright (C) 2013 - 2022 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2013 - 2024 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2025 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -55,7 +56,7 @@ SEXP testSendInterrupt() { SEXP maybeThrow(void* data) { bool* fail = (bool*) data; if (*fail) - Rf_error("throw!"); + (Rf_error)("throw!"); // prevent masking else return NumericVector::create(42); } diff --git a/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp b/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp index a6beb9b53..4b018f29f 100644 --- a/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp +++ b/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp @@ -43,7 +43,7 @@ RcppExport SEXP _testRcppInterfaceExporter_test_cpp_interface(SEXP xSEXP, SEXP f if (rcpp_isError_gen) { SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); UNPROTECT(1); - Rf_error("%s", CHAR(rcpp_msgSEXP_gen)); + (Rf_error)("%s", CHAR(rcpp_msgSEXP_gen)); } UNPROTECT(1); return rcpp_result_gen; diff --git a/src/attributes.cpp b/src/attributes.cpp index 81c2f5bef..5240e3627 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -2953,7 +2953,8 @@ namespace attributes { << " if (rcpp_isError_gen) {" << std::endl << " SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen);" << std::endl << " UNPROTECT(1);" << std::endl - << " Rf_error(\"%s\", CHAR(rcpp_msgSEXP_gen));" << std::endl + // Parentheses to prevent masking + << " (Rf_error)(\"%s\", CHAR(rcpp_msgSEXP_gen));" << std::endl << " }" << std::endl << " UNPROTECT(1);" << std::endl << " return rcpp_result_gen;" << std::endl