Skip to content

Commit

Permalink
fix basic_any on nvcc-12 and earlier
Browse files Browse the repository at this point in the history
part of this fix involves removing some deleted constructors that
prevented temporaries from binding to "const&" basic_any objects,
such as:

   std::ostream& operator<<( std::ostream& sout,  basic_any< iostreamable<> const & > obj );

   std::cout << MyWidget{}; // was disallowed, now ok

it is a change i have wanted to make anyway since a generic utility
like `basic_any` shouldn't be proscriptive about such things. Rather,
a type implemented in terms of `basic_any` might disallow such
potentially unsafe conversions.
  • Loading branch information
ericniebler committed Dec 13, 2024
1 parent fd1b467 commit 7036a62
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
#endif // no system header

#include <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/cstddef> // for byte

#include <cuda/experimental/__detail/utility.cuh>
#include <cuda/experimental/__utility/basic_any/basic_any_fwd.cuh>
#include <cuda/experimental/__utility/basic_any/interfaces.cuh>
#include <cuda/experimental/__utility/basic_any/storage.cuh>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#endif // no system header

#include <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__concepts/same_as.h>
#include <cuda/std/__type_traits/is_const.h>
#include <cuda/std/__type_traits/maybe_const.h>
#include <cuda/std/__type_traits/remove_const.h>
Expand Down Expand Up @@ -262,78 +263,58 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT basic_any<_Interface&> : basic_any<__irefer
using typename basic_any<__ireference<_Interface>>::interface_type;
using basic_any<__ireference<_Interface>>::__is_const_ref;

_CUDAX_TRIVIAL_HOST_API basic_any(basic_any&& __other) noexcept
: basic_any(const_cast<basic_any const&>(__other))
{}

_CUDAX_TRIVIAL_HOST_API basic_any(basic_any& __other) noexcept
: basic_any(const_cast<basic_any const&>(__other))
{}

_CUDAX_HOST_API basic_any(basic_any const& __other) noexcept
: basic_any<__ireference<_Interface>>()
{
this->__set_ref(__other.__get_vptr(), __other.__get_optr());
}

_CCCL_TEMPLATE(class _Tp, class _Up = _CUDA_VSTD::remove_const_t<_Tp>)
_CCCL_REQUIRES((!__is_basic_any<_Tp>) _CCCL_AND __satisfies<_Up, interface_type> _CCCL_AND(
__is_const_ref || !_CUDA_VSTD::is_const_v<_Tp>))
_CCCL_REQUIRES((!__is_basic_any<_Up>) _CCCL_AND(__is_const_ref || !_CUDA_VSTD::is_const_v<_Tp>)
_CCCL_AND __satisfies<_Up, interface_type>)
_CUDAX_HOST_API basic_any(_Tp& __obj) noexcept
: basic_any<__ireference<_Interface>>()
{
__vptr_for<interface_type> const __vptr = __cudax::__get_vtable_ptr_for<interface_type, _Up>();
this->__set_ref(__vptr, &__obj);
}

#if defined(_CCCL_CUDA_COMPILER_NVCC) && !defined(_CCCL_NO_CONCEPTS)
// For some reason, the constructor overloads below give nvcc fits when
// constrained with c++20 requires clauses. So we fall back to good ol'
// enable_if.
# define _CUDAX_TEMPLATE(...) template <__VA_ARGS__,
# define _CUDAX_REQUIRES(...) _CUDA_VSTD::enable_if_t<__VA_ARGS__, int> = 0 >
# define _CUDAX_AND , int > = 0, _CUDA_VSTD::enable_if_t <
#else // ^^^ NVCC && concepts ^^^ / vvv !NVCC || !concepts vvv
# define _CUDAX_TEMPLATE _CCCL_TEMPLATE
# define _CUDAX_REQUIRES _CCCL_REQUIRES
# define _CUDAX_AND _CCCL_AND
#endif // !NVCC || !concepts

_CUDAX_TEMPLATE(class _Tp)
_CUDAX_REQUIRES((!__is_basic_any<_Tp>) )
basic_any(_Tp const&&) = delete;

_CUDAX_TEMPLATE(class _SrcInterface)
_CUDAX_REQUIRES((!_CUDA_VSTD::same_as<_SrcInterface, _Interface&>) _CUDAX_AND //
(!__is_value_v<_SrcInterface>) _CUDAX_AND //
__any_convertible_to<basic_any<_SrcInterface>, basic_any>)
_CCCL_TEMPLATE(class _SrcInterface)
_CCCL_REQUIRES((!_CUDA_VSTD::same_as<_SrcInterface, _Interface&>) _CCCL_AND //
(!__is_value_v<_SrcInterface>) _CCCL_AND //
__any_convertible_to<basic_any<_SrcInterface>, basic_any>)
_CUDAX_HOST_API basic_any(basic_any<_SrcInterface>&& __src) noexcept
: basic_any<__ireference<_Interface>>()
{
this->__set_ref(__src.__get_vptr(), __src.__get_optr());
}

_CUDAX_TEMPLATE(class _SrcInterface)
_CUDAX_REQUIRES((!_CUDA_VSTD::same_as<_SrcInterface, _Interface&>) _CUDAX_AND //
__any_convertible_to<basic_any<_SrcInterface>&, basic_any>)
_CCCL_TEMPLATE(class _SrcInterface)
_CCCL_REQUIRES((!_CUDA_VSTD::same_as<_SrcInterface, _Interface&>) _CCCL_AND //
__any_convertible_to<basic_any<_SrcInterface>&, basic_any>)
_CUDAX_HOST_API basic_any(basic_any<_SrcInterface>& __src) noexcept
: basic_any<__ireference<_Interface>>()
{
this->__set_ref(__src.__get_vptr(), __src.__get_optr());
}

_CUDAX_TEMPLATE(class _SrcInterface)
_CUDAX_REQUIRES((!_CUDA_VSTD::same_as<_SrcInterface, _Interface&>) _CUDAX_AND //
__any_convertible_to<basic_any<_SrcInterface> const&, basic_any>)
_CCCL_TEMPLATE(class _SrcInterface)
_CCCL_REQUIRES((!_CUDA_VSTD::same_as<_SrcInterface, _Interface&>) _CCCL_AND //
__any_convertible_to<basic_any<_SrcInterface> const&, basic_any>)
_CUDAX_HOST_API basic_any(basic_any<_SrcInterface> const& __src) noexcept
: basic_any<__ireference<_Interface>>()
{
this->__set_ref(__src.__get_vptr(), __src.__get_optr());
}

// A temporary value cannot bind to a basic_any reference.
// TODO: find another way to support APIs that take by reference and want
// implicit conversion from prvalues.
_CUDAX_TEMPLATE(class _SrcInterface)
_CUDAX_REQUIRES(__is_value_v<_SrcInterface>) //
basic_any(basic_any<_SrcInterface> const&&) = delete;

#undef _CUDAX_AND
#undef _CUDAX_REQUIRES
#undef _CUDAX_TEMPLATE

auto operator=(basic_any&&) -> basic_any& = delete;
auto operator=(basic_any const&) -> basic_any& = delete;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <cuda/std/__concepts/concept_macros.h>
#include <cuda/std/__concepts/same_as.h>
#include <cuda/std/__new/launder.h>
#include <cuda/std/__type_traits/decay.h>
#include <cuda/std/__type_traits/is_class.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_same.h>
Expand Down Expand Up @@ -85,11 +86,11 @@ public:
//! \pre `__value` must be move constructible. `_Tp` must satisfy the
//! requirements of `_Interface`.
//! \post `has_value() == true`
_CCCL_TEMPLATE(class _Tp)
_CCCL_REQUIRES((!__is_basic_any<_Tp>) _CCCL_AND __satisfies<_Tp, _Interface>)
_CUDAX_HOST_API basic_any(_Tp __value) noexcept(__is_small<_Tp>(__size_, __align_))
_CCCL_TEMPLATE(class _Tp, class _Up = _CUDA_VSTD::decay_t<_Tp>)
_CCCL_REQUIRES((!__is_basic_any<_Up>) _CCCL_AND __satisfies<_Up, _Interface>)
_CUDAX_HOST_API basic_any(_Tp&& __value) noexcept(__is_small<_Up>(__size_, __align_))
{
__emplace<_Tp>(_CUDA_VSTD::move(__value));
__emplace<_Up>(static_cast<_Tp&&>(__value));
}

//! \brief Constructs a `basic_any` object that contains a new object of type
Expand Down Expand Up @@ -181,7 +182,14 @@ public:
// basic_any<__ireference<I>> and basic_any<I&>.
_CCCL_TEMPLATE(class _OtherInterface)
_CCCL_REQUIRES(__any_convertible_to<basic_any<_OtherInterface&>, basic_any>)
_CUDAX_HOST_API basic_any(basic_any<_OtherInterface&> __other)
_CUDAX_HOST_API basic_any(basic_any<_OtherInterface&>&& __other)
{
__convert_from(__other);
}

_CCCL_TEMPLATE(class _OtherInterface)
_CCCL_REQUIRES(__any_convertible_to<basic_any<_OtherInterface&>, basic_any>)
_CUDAX_HOST_API basic_any(basic_any<_OtherInterface&> const& __other)
{
__convert_from(__other);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
_CCCL_PUSH_MACROS
#undef interface

#if defined(_CCCL_CUDA_COMPILER_NVCC) || defined(_CCCL_CUDA_COMPILER_NVHPC)
#if _CCCL_CUDA_COMPILER(NVCC) || _CCCL_CUDA_COMPILER(NVHPC)
// WAR for NVBUG #4924416
# define _CUDAX_FNPTR_CONSTANT_WAR(...) ::cuda::experimental::__constant_war(__VA_ARGS__)
namespace cuda::experimental
Expand All @@ -52,10 +52,10 @@ _CCCL_NODISCARD _CUDAX_HOST_API constexpr _Tp __constant_war(_Tp __val) noexcept
return __val;
}
} // namespace cuda::experimental
#else // ^^^ defined(_CCCL_CUDA_COMPILER_NVCC) || defined(_CCCL_CUDA_COMPILER_NVHPC) ^^^ /
// vvv !defined(_CCCL_CUDA_COMPILER_NVCC) && !defined(_CCCL_CUDA_COMPILER_NVHPC) vvv
#else // ^^^ _CCCL_CUDA_COMPILER(NVCC) || _CCCL_CUDA_COMPILER(NVHPC) ^^^ /
// vvv !_CCCL_CUDA_COMPILER(NVCC) && !_CCCL_CUDA_COMPILER(NVHPC) vvv
# define _CUDAX_FNPTR_CONSTANT_WAR(...) __VA_ARGS__
#endif // !defined(_CCCL_CUDA_COMPILER_NVCC) && !defined(_CCCL_CUDA_COMPILER_NVHPC)
#endif // !_CCCL_CUDA_COMPILER(NVCC) && !_CCCL_CUDA_COMPILER(NVHPC)

namespace cuda::experimental
{
Expand Down
2 changes: 1 addition & 1 deletion cudax/test/utility/basic_any.cu
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ TEMPLATE_TEST_CASE_METHOD(BasicAnyTestsFixture, "basic_any tests", "[utility][ba
!_CUDA_VSTD::constructible_from<cudax::basic_any<cudax::imovable<>>, cudax::basic_any<cudax::imovable<>*>>);

STATIC_REQUIRE(
!_CUDA_VSTD::constructible_from<cudax::basic_any<cudax::imovable<> const&>, cudax::basic_any<cudax::imovable<>>>);
_CUDA_VSTD::constructible_from<cudax::basic_any<cudax::imovable<> const&>, cudax::basic_any<cudax::imovable<>>>);
STATIC_REQUIRE(
_CUDA_VSTD::constructible_from<cudax::basic_any<cudax::imovable<> const&>, cudax::basic_any<cudax::imovable<>>&>);
}
Expand Down

0 comments on commit 7036a62

Please sign in to comment.