diff --git a/libcudacxx/include/cuda/__utility/__basic_any/basic_any_value.h b/libcudacxx/include/cuda/__utility/__basic_any/basic_any_value.h index 2fd5ae0184a..c8fd21c8b58 100644 --- a/libcudacxx/include/cuda/__utility/__basic_any/basic_any_value.h +++ b/libcudacxx/include/cuda/__utility/__basic_any/basic_any_value.h @@ -147,7 +147,7 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __basic_any : __basic_any_base<_Interface> //! @post `__other.has_value() == false` and `has_value()` is `true` if and //! only if `__other.has_value()` was `true`. _CCCL_TEMPLATE(class _OtherInterface) - _CCCL_REQUIRES((!::cuda::std::same_as<_OtherInterface, _Interface>) + _CCCL_REQUIRES((!::cuda::std::same_as<_OtherInterface&, _Interface&>) _CCCL_AND __any_convertible_to<__basic_any<_OtherInterface>, __basic_any>) _CCCL_API __basic_any(__basic_any<_OtherInterface>&& __other) { @@ -160,13 +160,33 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __basic_any : __basic_any_base<_Interface> //! `__icopyable<>`. //! @post `has_value() == __other.has_value()`. _CCCL_TEMPLATE(class _OtherInterface) - _CCCL_REQUIRES((!::cuda::std::same_as<_OtherInterface, _Interface>) + _CCCL_REQUIRES((!::cuda::std::same_as<_OtherInterface&, _Interface&>) _CCCL_AND __any_convertible_to<__basic_any<_OtherInterface> const&, __basic_any>) _CCCL_API __basic_any(__basic_any<_OtherInterface> const& __other) { __convert_from(__other); } + //! @brief Non-template converting constructors from the corresponding + //! reference type `__basic_any<_Interface&>`. These enable implicit + //! conversion from proxy types (e.g. Cython's __Pyx_FakeReference) + //! that wrap a `__basic_any<_Interface&>` and provide + //! `operator __basic_any<_Interface&>&()`, since non-template parameters + //! participate in implicit conversion sequences. + //! @pre `_Interface` must extend `__icopyable<>` (converting a ref to + //! a value requires copying the referenced object). + template = 0> + _CCCL_API __basic_any(__basic_any<_Interface&> const& __other) + { + __convert_from(__other); + } + + template = 0> + _CCCL_API __basic_any(__basic_any<_Interface&>&& __other) + { + __convert_from(__other); + } + #if _CCCL_COMPILER(CLANG, <, 12) || _CCCL_COMPILER(GCC, <, 11) // Older versions of clang and gcc need help disambiguating between // __basic_any<__ireference> and __basic_any. diff --git a/libcudacxx/test/libcudacxx/cuda/memory_resource/any_resource/any_resource.cu b/libcudacxx/test/libcudacxx/cuda/memory_resource/any_resource/any_resource.cu index 7cb60d165e6..c4c2d04d814 100644 --- a/libcudacxx/test/libcudacxx/cuda/memory_resource/any_resource/any_resource.cu +++ b/libcudacxx/test/libcudacxx/cuda/memory_resource/any_resource/any_resource.cu @@ -348,4 +348,83 @@ TEST_CASE("regression test for NVIDIA/cccl#8037", "[container][resource]") { STATIC_REQUIRE(cuda::std::move_constructible); } + +// Minimal proxy that wraps a value and provides operator T&(), mimicking +// Cython's __Pyx_FakeReference which wraps intermediate expression results. +template +struct value_proxy +{ + T value; + + template + explicit value_proxy(Args&&... args) + : value(std::forward(args)...) + {} + + operator T&() + { + return value; + } +}; + +// See https://github.com/NVIDIA/cccl/issues/8316 +TEST_CASE("any_resource from proxy-wrapped resource_ref", "[container][resource]") +{ + host_device_resource mr; + cuda::mr::resource_ref ref{mr}; + + SECTION("direct construction from resource_ref") + { + cuda::mr::any_resource any{ref}; + // Extra parens prevent Catch2's expression decomposition, which triggers + // an nvcc bug with auto NTTP deduction in __satisfies during ADL. + CHECK((any == ref)); + } + +# if !_CCCL_CUDA_COMPILER(NVCC, <, 12, 9) + // nvcc before CTK 12.9 has a bug where auto NTTP deduction failures in + // __satisfies are hard errors instead of SFINAE during overload resolution. + SECTION("construction from lvalue proxy-wrapped resource_ref") + { + value_proxy> proxy{mr}; + cuda::mr::any_resource any{proxy}; + CHECK((any == ref)); + } + + SECTION("construction from rvalue proxy-wrapped resource_ref") + { + cuda::mr::any_resource any{ + value_proxy>{mr}}; + CHECK((any == ref)); + } +# endif // !_CCCL_CUDA_COMPILER(NVCC, <, 12, 9) +} + +TEST_CASE("any_synchronous_resource from proxy-wrapped synchronous_resource_ref", "[container][resource]") +{ + host_device_resource mr; + cuda::mr::synchronous_resource_ref ref{mr}; + + SECTION("direct construction from synchronous_resource_ref") + { + cuda::mr::any_synchronous_resource any{ref}; + CHECK((any == ref)); + } + +# if !_CCCL_CUDA_COMPILER(NVCC, <, 12, 9) + SECTION("construction from lvalue proxy-wrapped synchronous_resource_ref") + { + value_proxy> proxy{mr}; + cuda::mr::any_synchronous_resource any{proxy}; + CHECK((any == ref)); + } + + SECTION("construction from rvalue proxy-wrapped synchronous_resource_ref") + { + cuda::mr::any_synchronous_resource any{ + value_proxy>{mr}}; + CHECK((any == ref)); + } +# endif // !_CCCL_CUDA_COMPILER(NVCC, <, 12, 9) +} #endif // __CUDA_ARCH__