From 3863884b58647137d03b30a83b4020adba595b15 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/4] Lay the ground for Rf_error masking (#1402) * Add a message at compilation time * Protect the valid Rf_error calls generated by Rcpp --- ChangeLog | 11 ++++++- inst/include/Rcpp/macros/mask.h | 33 +++++++++++++++++++ inst/include/RcppCommon.h | 2 ++ inst/tinytest/cpp/stack.cpp | 5 +-- .../src/RcppExports.cpp | 2 +- src/attributes.cpp | 3 +- 6 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 inst/include/Rcpp/macros/mask.h diff --git a/ChangeLog b/ChangeLog index 300534ae1..ab150f339 100644 --- a/ChangeLog +++ b/ChangeLog @@ -44,6 +44,15 @@ * inst/include/Rcpp/r/check_r_headers.h: New header to check if R.h or related R headers were installed first * inst/include/RcppCommon.h: Call new header as first thing +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 @@ -57,7 +66,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 b4752845e..18671e86f 100644 --- a/inst/include/RcppCommon.h +++ b/inst/include/RcppCommon.h @@ -190,4 +190,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 263406c9cb75e3f89056be23fb86c6712f82e18d 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/4] 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 ab150f339..8cdcc2f13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -46,9 +46,8 @@ * inst/include/RcppCommon.h: Call new header as first thing 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 0db994df00c561e0b3a31b1b768dbb35b7fd521c 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/4] 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 8cdcc2f13..8cabe83aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -47,7 +47,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\ From 461e8ad21dc9f21492b9ae9b2d97148fc490c4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Tue, 9 Dec 2025 13:42:33 +0100 Subject: [PATCH 4/4] rebase fix --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 8cabe83aa..2f1d179b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -44,6 +44,7 @@ * inst/include/Rcpp/r/check_r_headers.h: New header to check if R.h or related R headers were installed first * inst/include/RcppCommon.h: Call new header as first thing + 2025-11-12 Iñaki Ucar * inst/include/Rcpp/macros/mask.h: Lay the ground for Rf_error masking