Skip to content

Commit

Permalink
Fix swapping types from namespace std
Browse files Browse the repository at this point in the history
  • Loading branch information
bernhardmgruber committed Dec 3, 2024
1 parent 5d21491 commit 6b82f20
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 12 deletions.
3 changes: 2 additions & 1 deletion libcudacxx/include/cuda/std/__type_traits/is_swappable.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <cuda/std/__type_traits/is_same.h>
#include <cuda/std/__type_traits/is_void.h>
#include <cuda/std/__type_traits/nat.h>
#include <cuda/std/__type_traits/type_identity.h>
#include <cuda/std/__utility/declval.h>
#include <cuda/std/cstddef>

Expand Down Expand Up @@ -101,7 +102,7 @@ using __swap_result_t _CCCL_NODEBUG_ALIAS =
&& _CCCL_TRAIT(is_move_assignable, _Tp)>;

template <class _Tp>
_LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX14 __swap_result_t<_Tp> swap(_Tp& __x, _Tp& __y) noexcept(
_LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX14 __swap_result_t<_Tp> swap(_Tp& __x, type_identity_t<_Tp>& __y) noexcept(
_CCCL_TRAIT(is_nothrow_move_constructible, _Tp) && _CCCL_TRAIT(is_nothrow_move_assignable, _Tp));

template <class _Tp, size_t _Np>
Expand Down
6 changes: 5 additions & 1 deletion libcudacxx/include/cuda/std/__utility/swap.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@

_LIBCUDACXX_BEGIN_NAMESPACE_STD

// we use type_identity_t<_Tp> as second parameter, to avoid ambiguity with std::swap, which will thus be preferred by
// overload resolution (which is ok since std::swap is only considered when explicitly called, or found by ADL for types
// from std::)
_CCCL_EXEC_CHECK_DISABLE
template <class _Tp>
_LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX14 __swap_result_t<_Tp> swap(_Tp& __x, _Tp& __y) noexcept(
_LIBCUDACXX_HIDE_FROM_ABI _CCCL_CONSTEXPR_CXX14 __swap_result_t<_Tp> swap(_Tp& __x, type_identity_t<_Tp>& __y) noexcept(
_CCCL_TRAIT(is_nothrow_move_constructible, _Tp) && _CCCL_TRAIT(is_nothrow_move_assignable, _Tp))
// requires(!requires{ ::std::swap(__x, __y); })
{
_Tp __t(_CUDA_VSTD::move(__x));
__x = _CUDA_VSTD::move(__y);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "test_macros.h"

#if !defined(TEST_COMPILER_NVRTC)
# include <memory>
# include <utility>
#endif // !TEST_COMPILER_NVRTC

Expand Down Expand Up @@ -102,26 +103,50 @@ struct swap_with_friend
__host__ __device__ friend void swap(swap_with_friend&, swap_with_friend&) {}
};

template <typename T>
__host__ __device__ void test_ambiguous_std()
{
#if !defined(TEST_COMPILER_NVRTC)
// clang-format off
NV_IF_TARGET(NV_IS_HOST, (
// fully qualified calls
{
cuda::std::pair<::std::pair<int, int>, int> i = {};
cuda::std::pair<::std::pair<int, int>, int> j = {};
T i = {};
T j = {};
cuda::std::swap(i,j);
}
{
T i = {};
T j = {};
std::swap(i,j);
}
// ADL calls
{
T i = {};
T j = {};
swap(i,j);
}
{
T i = {};
T j = {};
using cuda::std::swap;
swap(i,j);
}
{
T i = {};
T j = {};
using std::swap;
swap(i,j);
}
{ // Ensure that we do not SFINAE swap out if there is a free function as that will take precedent
swap_with_friend<::std::pair<int, int>> with_friend;
cuda::std::swap(with_friend, with_friend);
{
T i = {};
T j = {};
using std::swap;
using cuda::std::swap;
swap(i,j);
}
))
// clang-format on
# if TEST_STD_VER >= 2014
static_assert(cuda::std::is_swappable<cuda::std::pair<::std::pair<int, int>, int>>::value, "");
static_assert(cuda::std::is_swappable<swap_with_friend<::std::pair<int, int>>>::value, "");
# endif // TEST_STD_VER >= 2014
#endif // !TEST_COMPILER_NVRTC
}

Expand Down Expand Up @@ -162,7 +187,17 @@ int main(int, char**)
static_assert(test_swap_constexpr(), "");
#endif // TEST_STD_VER >= 2014

test_ambiguous_std();
test_ambiguous_std<cuda::std::pair<::std::pair<int, int>, int>>(); // has std:: and cuda::std as associated namespaces
test_ambiguous_std<::std::pair<int, int>>(); // has std::swap overload
test_ambiguous_std<::std::allocator<char>>(); // no std::swap overload

// Ensure that we do not SFINAE swap out if there is a free function as that will take precedent
test_ambiguous_std<swap_with_friend<::std::pair<int, int>>>();

#if TEST_STD_VER >= 2014
static_assert(cuda::std::is_swappable<cuda::std::pair<::std::pair<int, int>, int>>::value, "");
static_assert(cuda::std::is_swappable<swap_with_friend<::std::pair<int, int>>>::value, "");
#endif // TEST_STD_VER >= 2014

return 0;
}

0 comments on commit 6b82f20

Please sign in to comment.