From 414001b428c36d68fe696292a43e85a88ad26746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Wed, 12 Nov 2025 18:19:21 +0100 Subject: [PATCH 1/3] Lay the ground for Rf_error masking (#1402) * Add a message at compilation time * Protect the valid Rf_error calls generated by Rcpp --- ChangeLog | 12 ++++++- inst/include/Rcpp/macros/mask.h | 33 +++++++++++++++++++ inst/include/RcppCommon.h | 4 ++- inst/tinytest/cpp/stack.cpp | 5 +-- .../src/RcppExports.cpp | 2 +- src/attributes.cpp | 3 +- 6 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 inst/include/Rcpp/macros/mask.h diff --git a/ChangeLog b/ChangeLog index 9911a8173..f31997a14 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2025-11-12 Iñaki Ucar + + * inst/include/Rcpp/macros/mask.h: Lay the ground for Rf_error masking, + unless RCPP_NO_MASK_RF_ERROR is defined; the new define just generates a + compilation note, which will become a warning + masking in a future release + * 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-11-04 Dirk Eddelbuettel * .github/workflows/macos.yaml (jobs): Roll macos-13 to macos-14 @@ -10,7 +20,7 @@ 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..a9da61f79 --- /dev/null +++ b/inst/include/Rcpp/macros/mask.h @@ -0,0 +1,33 @@ +// 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("message \"Use of Rf_error() instead of 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. More info:\n\ + - https://github.com/RcppCore/Rcpp/issues/1247\n\ + - https://github.com/RcppCore/Rcpp/pull/1402\"") \ + Rf_error(__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 From 088535b892edcc3f881f21d0465416fd2bd7e4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Wed, 12 Nov 2025 18:28:36 +0100 Subject: [PATCH 2/3] some rewording to fit the ChangeLog text in two lines --- ChangeLog | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index f31997a14..3b3da46b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,7 @@ 2025-11-12 Iñaki Ucar - * inst/include/Rcpp/macros/mask.h: Lay the ground for Rf_error masking, - unless RCPP_NO_MASK_RF_ERROR is defined; the new define just generates a - compilation note, which will become a warning + masking in a future release + * inst/include/Rcpp/macros/mask.h: Lay the ground for Rf_error masking + with a message 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 From ce5cee3593c92aa125918ce87ea18f9fd424aa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Fri, 14 Nov 2025 10:36:29 +0100 Subject: [PATCH 3/3] messages are considered statements by gcc and cannot be used safely; switching to a warning --- ChangeLog | 2 +- inst/include/Rcpp/macros/mask.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b3da46b4..1bc9e3dea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ 2025-11-12 Iñaki Ucar * inst/include/Rcpp/macros/mask.h: Lay the ground for Rf_error masking - with a message at compilation time unless RCPP_NO_MASK_RF_ERROR is defined + 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 diff --git a/inst/include/Rcpp/macros/mask.h b/inst/include/Rcpp/macros/mask.h index a9da61f79..4f065ad8e 100644 --- a/inst/include/Rcpp/macros/mask.h +++ b/inst/include/Rcpp/macros/mask.h @@ -22,7 +22,7 @@ #ifndef RCPP_NO_MASK_RF_ERROR #define Rf_error(...) \ - _Pragma("message \"Use of Rf_error() instead of Rcpp::stop(). Calls \ + _Pragma("GCC warning \"Use of Rf_error() instead of 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. More info:\n\ - https://github.com/RcppCore/Rcpp/issues/1247\n\