diff --git a/ChangeLog b/ChangeLog index f80d4f939..fdf695f6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2026-06-26 Kevin Ushey + + * inst/include/Rcpp/proxy/AttributeProxy.h: Do not rely on get__() + in attribute accessors so that classes such as ListOf compile + * inst/tinytest/cpp/ListOf.cpp: Added tests + * inst/tinytest/test_listof.R: Idem + 2026-06-23 Jeroen Ooms * Add templated integer-index overload on platforms without diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 75b6467fd..18086f373 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -36,6 +36,9 @@ has been fixed (Kevin in \ghpr{1475} fixing \ghit{1474}) \item The \code{Nullable::operatorT()} has been added as a 'opt-out' (Dirk in \ghpr{1477} with coordination in \ghit{1472}) + \item The attribute accessors in \code{AttributeProxyPolicy} no longer + rely on \code{get__()} so that classes such as \code{ListOf} compile + (Kevin in \ghpr{1484} fixing \ghit{1483}) } \item Changes in Rcpp Documentation: \itemize{ diff --git a/inst/include/Rcpp/proxy/AttributeProxy.h b/inst/include/Rcpp/proxy/AttributeProxy.h index f3e31466f..859d67632 100644 --- a/inst/include/Rcpp/proxy/AttributeProxy.h +++ b/inst/include/Rcpp/proxy/AttributeProxy.h @@ -86,7 +86,7 @@ class AttributeProxyPolicy { v.push_back(std::string(CHAR(STRING_ELT(attrs, i)))); } #else - SEXP attrs = ATTRIB( static_cast(*this).get__()); + SEXP attrs = ATTRIB( static_cast(*this) ); while( attrs != R_NilValue ){ v.push_back( std::string(CHAR(PRINTNAME(TAG(attrs)))) ) ; attrs = CDR( attrs ) ; @@ -97,7 +97,7 @@ class AttributeProxyPolicy { bool hasAttribute(const std::string& attr) const { #if R_VERSION >= R_Version(4, 6, 0) - return R_hasAttrib(static_cast(*this).get__(), Rf_install(attr.c_str())); + return R_hasAttrib(static_cast(*this), Rf_install(attr.c_str())); #else return static_cast(*this).attr(attr) != R_NilValue; #endif diff --git a/inst/tinytest/cpp/ListOf.cpp b/inst/tinytest/cpp/ListOf.cpp index 05af92d61..9a5687b02 100644 --- a/inst/tinytest/cpp/ListOf.cpp +++ b/inst/tinytest/cpp/ListOf.cpp @@ -113,3 +113,13 @@ CharacterVector listof_names(ListOf x) { SEXP listof_attr_foo(ListOf x) { return x.attr("foo"); } + +// [[Rcpp::export]] +bool listof_has_attr(ListOf x, std::string name) { + return x.hasAttribute(name); +} + +// [[Rcpp::export]] +std::vector listof_attribute_names(ListOf x) { + return x.attributeNames(); +} diff --git a/inst/tinytest/test_listof.R b/inst/tinytest/test_listof.R index 46ed68c8f..f46cd528d 100644 --- a/inst/tinytest/test_listof.R +++ b/inst/tinytest/test_listof.R @@ -72,3 +72,15 @@ expect_equal(listof_names(l), c("a", "b", "c")) l <- list(a = 1L) attr(l, "foo") <- "bar" expect_equal(listof_attr_foo(l), "bar") + +# test.ListOf.has.attribute <- function() { # GH issue #1483 +l <- list(a = 1L) +attr(l, "foo") <- "bar" +expect_true(listof_has_attr(l, "foo")) +expect_true(listof_has_attr(l, "names")) +expect_false(listof_has_attr(l, "missing")) + +# test.ListOf.attribute.names <- function() { # GH issue #1483 +l <- list(a = 1L) +attr(l, "foo") <- "bar" +expect_true(all(c("names", "foo") %in% listof_attribute_names(l)))