Skip to content

Fix ambiguous Vector::operator[] on platforms without LONG_VECTOR_SUPPORT (wasm32)#1482

Open
jeroen wants to merge 1 commit into
RcppCore:masterfrom
jeroen:wasm-subscript-fix
Open

Fix ambiguous Vector::operator[] on platforms without LONG_VECTOR_SUPPORT (wasm32)#1482
jeroen wants to merge 1 commit into
RcppCore:masterfrom
jeroen:wasm-subscript-fix

Conversation

@jeroen

@jeroen jeroen commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Problem

On the wasm32 target (e.g. r-universe webR builds), packages that subscript an Rcpp::Vector with an integer index whose type is not exactly R_xlen_t now fail to compile with an overload-resolution ambiguity. The originally reported failure was in ulid with a long index:

wrapper.cpp:33:10: error: use of overloaded operator '[]' is ambiguous
   (with operand types 'Rcpp::CharacterVector' (aka 'Vector<16>') and 'long')
   33 |         c[i] = ulid::Marshal(ulid::CreateNowRand());

with candidates:

  • Vector::operator[](R_xlen_t)inst/include/Rcpp/vector/Vector.h:338
  • built-in operator[](SEXPREC*, __ptrdiff_t) — synthesised because Rcpp::Vector has an implicit operator SEXP() const via PreserveStorage.

The same shape of error also occurs in Rcpp's own headers (newDateVector.h, newDatetimeVector.h, module/Module.h, module/class.h, …) any time a member uses a size_t loop variable to subscript a Vector.

Root cause

R defines R_xlen_t as ptrdiff_t only when LONG_VECTOR_SUPPORT is set (i.e. sizeof(size_t) > 4). On wasm32 that macro is not defined and R_xlen_t falls back to int, while ptrdiff_t remains long. So for c[i] with i of any integer type wider than int:

  • Member candidate: identity on object, integral conversion on the index.
  • Built-in candidate: user-defined conversion Vector -> SEXP on object, exact match (or narrower conversion) on the index.

The two implicit conversion sequences are mutually unrankable, so the call is ambiguous. On LP64 platforms R_xlen_t == ptrdiff_t == long, the member matches a long index exactly and wins outright; the ambiguity is wasm-specific.

Fix

Add a SFINAE-constrained template overload of Vector::operator[] that accepts any integral index type other than R_xlen_t itself and delegates to the existing R_xlen_t overload with a static_cast. The template provides an identity match on the index argument, so it beats both:

  • the non-template R_xlen_t overload (which would require an integral conversion), and
  • the built-in pointer subscript (which would require a user-defined conversion on the object).

When the index is exactly R_xlen_t, the SFINAE constraint excludes the template and the existing non-template overload is selected as before.

The new overload is compiled only when LONG_VECTOR_SUPPORT is not defined, so the overload set on LP64 / LLP64 platforms is unchanged. Marking operator SEXP() explicit would be the alternative root-cause fix but is far too disruptive — implicit SEXP conversion is load-bearing for nearly every downstream package.

Test plan

  • Existing CI matrix (Linux x86_64/arm64, macOS x86_64/arm64, Windows) — overload set unchanged on LP64/LLP64.
  • r-universe wasm build of an affected package (e.g. ulid) succeeds after this patch.

🤖 Generated with Claude Code

Comment thread inst/include/Rcpp/vector/Vector.h

@eddelbuettel eddelbuettel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One gentle nudge for change inline.

Comment thread ChangeLog Outdated
@jeroen jeroen force-pushed the wasm-subscript-fix branch from 8951335 to 158c1a1 Compare June 23, 2026 18:56
…PORT

On wasm32 (and other platforms where LONG_VECTOR_SUPPORT is not
defined) R_xlen_t is int while ptrdiff_t is long. Subscripting an
Rcpp::Vector with a long index then becomes ambiguous between the
member operator[] (which needs a long -> int conversion on the index)
and the built-in pointer subscript operator[](SEXPREC*, ptrdiff_t)
synthesised via the implicit Vector -> SEXP conversion (which needs a
user-defined conversion on the object but matches the index exactly).
The two implicit conversion sequences are mutually unrankable so
overload resolution fails.
@jeroen jeroen force-pushed the wasm-subscript-fix branch from 158c1a1 to 708a0ec Compare June 23, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants