Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libcudacxx/include/cuda/std/__cccl/builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,10 @@
# define _CCCL_BUILTIN_TYPE_PACK_ELEMENT(...) __type_pack_element<__VA_ARGS__>
#endif // _CCCL_HAS_BUILTIN(__type_pack_element)

#if _CCCL_HAS_BUILTIN(__is_complete_type)
# define _CCCL_BUILTIN_IS_COMPLETE_TYPE(...) __is_complete_type(__VA_ARGS__)
#endif // _CCCL_HAS_BUILTIN(__is_complete_type)

// NVCC prior to 12.2 have trouble with pack expansion into __type_pack_element in an alias template
#if _CCCL_CUDACC_BELOW(12, 2)
# undef _CCCL_BUILTIN_TYPE_PACK_ELEMENT
Expand Down
9 changes: 6 additions & 3 deletions libcudacxx/include/cuda/std/__mdspan/empty_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <cuda/std/__type_traits/is_empty.h>
#include <cuda/std/__type_traits/is_nothrow_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_swappable.h>
#include <cuda/std/__type_traits/remove_cvref.h>
#include <cuda/std/__utility/forward.h>

Expand Down Expand Up @@ -127,7 +128,7 @@ struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco<_Elem1> : __mdspan_ebco_impl<0,
}

_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y)
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y) noexcept(is_nothrow_swappable_v<_Elem1>)
{
swap(__x.__get<0>(), __y.__get<0>());
}
Expand Down Expand Up @@ -219,7 +220,8 @@ struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco<_Elem1, _Elem2>
}

_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y)
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y) noexcept(
is_nothrow_swappable_v<_Elem1> && is_nothrow_swappable_v<_Elem2>)
{
swap(__x.__get<0>(), __y.__get<0>());
swap(__x.__get<1>(), __y.__get<1>());
Expand Down Expand Up @@ -346,7 +348,8 @@ struct _CCCL_DECLSPEC_EMPTY_BASES __mdspan_ebco<_Elem1, _Elem2, _Elem3>
}

_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y)
_CCCL_API friend constexpr void swap(__mdspan_ebco& __x, __mdspan_ebco& __y) noexcept(
is_nothrow_swappable_v<_Elem1> && is_nothrow_swappable_v<_Elem2> && is_nothrow_swappable_v<_Elem3>)
{
swap(__x.__get<0>(), __y.__get<0>());
swap(__x.__get<1>(), __y.__get<1>());
Expand Down
10 changes: 7 additions & 3 deletions libcudacxx/include/cuda/std/__ranges/compressed_movable_box.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <cuda/std/__type_traits/is_nothrow_default_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_assignable.h>
#include <cuda/std/__type_traits/is_nothrow_move_constructible.h>
#include <cuda/std/__type_traits/is_swappable.h>
#include <cuda/std/__type_traits/is_trivially_copy_assignable.h>
#include <cuda/std/__type_traits/is_trivially_copy_constructible.h>
#include <cuda/std/__type_traits/is_trivially_destructible.h>
Expand Down Expand Up @@ -667,7 +668,8 @@ struct _CCCL_DECLSPEC_EMPTY_BASES __compressed_movable_box<_Elem1> : __compresse
}

_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__compressed_movable_box& __x, __compressed_movable_box& __y)
_CCCL_API friend constexpr void
swap(__compressed_movable_box& __x, __compressed_movable_box& __y) noexcept(is_nothrow_swappable_v<_Elem1>)
{
swap(__x.__get<0>(), __y.__get<0>());
}
Expand Down Expand Up @@ -752,7 +754,8 @@ struct _CCCL_DECLSPEC_EMPTY_BASES __compressed_movable_box<_Elem1, _Elem2>
}

_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__compressed_movable_box& __x, __compressed_movable_box& __y)
_CCCL_API friend constexpr void swap(__compressed_movable_box& __x, __compressed_movable_box& __y) noexcept(
is_nothrow_swappable_v<_Elem1> && is_nothrow_swappable_v<_Elem2>)
{
swap(__x.__get<0>(), __y.__get<0>());
swap(__x.__get<1>(), __y.__get<1>());
Expand Down Expand Up @@ -874,7 +877,8 @@ struct _CCCL_DECLSPEC_EMPTY_BASES __compressed_movable_box<_Elem1, _Elem2, _Elem
}

_CCCL_EXEC_CHECK_DISABLE
_CCCL_API friend constexpr void swap(__compressed_movable_box& __x, __compressed_movable_box& __y)
_CCCL_API friend constexpr void swap(__compressed_movable_box& __x, __compressed_movable_box& __y) noexcept(
is_nothrow_swappable_v<_Elem1> && is_nothrow_swappable_v<_Elem2> && is_nothrow_swappable_v<_Elem3>)
{
swap(__x.__get<0>(), __y.__get<0>());
swap(__x.__get<1>(), __y.__get<1>());
Expand Down
4 changes: 2 additions & 2 deletions libcudacxx/include/cuda/std/__tuple_dir/tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,12 @@ class _CCCL_TYPE_VISIBILITY_DEFAULT tuple
return *this;
}

_CCCL_API void swap(tuple& __t)
_CCCL_API void swap(tuple& __t) noexcept(noexcept(__base_.swap(__t.__base_)))
{
__base_.swap(__t.__base_);
}

_CCCL_API friend void swap(tuple& __t, tuple& __u)
_CCCL_API friend void swap(tuple& __t, tuple& __u) noexcept(noexcept(__t.swap(__u)))
{
__t.swap(__u);
}
Expand Down
14 changes: 13 additions & 1 deletion libcudacxx/include/cuda/std/__tuple_dir/tuple_leaf.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,19 @@ struct _CCCL_DECLSPEC_EMPTY_BASES __tuple_impl<__tuple_indices<_Indx...>, _Tp...
_CCCL_HIDE_FROM_ABI __tuple_impl& operator=(__tuple_impl&&) = default;

// Using a fold exppression here breaks nvrtc
_CCCL_API inline void swap(__tuple_impl& __t) noexcept(__fold_and_v<is_nothrow_swappable_v<_Tp>...>)
_CCCL_API inline void swap(__tuple_impl& __t)
// NVCC 12.0.X has a bug where it instantiates friend functions eagerly. This leads to errors
// because the friend swap() in tuple causes this swap() to (transitively) be instantiated
// regardless of whether it is called or not.
//
// When using tuples of incomplete types this causes errors with is_nothrow_swappable (or
// rather, any is_swappable trait) as they require the types to be complete. In this case we
// need to lazily instantiate these templates so we can short-circuit if _Tp is incomplete.
#if _CCCL_CUDA_COMPILER(NVCC, <, 12, 1)
noexcept(__fold_and_v<__is_complete_and_nothrow_swappable_v<remove_cvref_t<_Tp>>...>)
#else // ^^^ _CCCL_CUDA_COMPILER(NVCC, <, 12, 1) ^^^ / vvv _CCCL_CUDA_COMPILER(NVCC, >=, 12, 1) vvv
noexcept(__fold_and_v<is_nothrow_swappable_v<_Tp>...>)
#endif // _CCCL_CUDA_COMPILER(NVCC, <, 12, 1)
{
(__tuple_leaf<_Indx, _Tp>::swap(static_cast<__tuple_leaf<_Indx, _Tp>&>(__t)), ...);
}
Expand Down
53 changes: 53 additions & 0 deletions libcudacxx/include/cuda/std/__type_traits/is_complete.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// Part of libcu++, the C++ Standard Library for your entire system,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//

#ifndef _CUDA_STD___TYPE_TRAITS_IS_COMPLETE_H
#define _CUDA_STD___TYPE_TRAITS_IS_COMPLETE_H

#include <cuda/std/detail/__config>

#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
# pragma GCC system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
# pragma clang system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
# pragma system_header
#endif // no system header

#include <cuda/std/__type_traits/void_t.h> // IWYU pragma: keep

#include <cuda/std/__cccl/prologue.h>

_CCCL_BEGIN_NAMESPACE_CUDA_STD

#ifdef _CCCL_BUILTIN_IS_COMPLETE_TYPE

template <typename T>
inline constexpr bool __is_complete_v = _CCCL_BUILTIN_IS_COMPLETE_TYPE(T);

#else // ^^^ _CCCL_BUILTIN_IS_COMPLETE_TYPE ^^^ / vvv no builtin vvv
// Must be a SFINAE trait instead of
//
// template <typename T>
// inline constexpr __is_complete_v = sizeof(T) > 0;
//
// Because older NVCC doesn't even allow you to utter the phrase sizeof(T) if T is incomplete
template <typename T, typename = void>
inline constexpr bool __is_complete_v = false;

template <typename T>
inline constexpr bool __is_complete_v<T, void_t<decltype(sizeof(T))>> = (sizeof(T) > 0);
#endif // ^^^ no builtin ^^^

_CCCL_END_NAMESPACE_CUDA_STD

#include <cuda/std/__cccl/epilogue.h>

#endif // _CUDA_STD___TYPE_TRAITS_IS_COMPLETE_H
13 changes: 12 additions & 1 deletion libcudacxx/include/cuda/std/__type_traits/is_swappable.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <cuda/std/__type_traits/conditional.h>
#include <cuda/std/__type_traits/disjunction.h>
#include <cuda/std/__type_traits/enable_if.h>
#include <cuda/std/__type_traits/integral_constant.h>
#include <cuda/std/__type_traits/is_complete.h>
#include <cuda/std/__type_traits/is_move_assignable.h>
#include <cuda/std/__type_traits/is_move_constructible.h>
#include <cuda/std/__type_traits/is_nothrow_move_assignable.h>
Expand All @@ -49,7 +51,7 @@ namespace __detect_hidden_friend_swap
// This will intentionally create an ambiguity with std::swap if that is find-able by ADL. But it will not interfere
// with hidden friend swap
template <class _Tp>
_CCCL_HOST_DEVICE void swap(_Tp&, _Tp&);
_CCCL_HOST_DEVICE void swap(_Tp&, _Tp&); // NOLINT(performance-noexcept-swap)

struct __hidden_friend_swap_found
{};
Expand Down Expand Up @@ -193,6 +195,15 @@ template <class _Tp>
struct _CCCL_TYPE_VISIBILITY_DEFAULT is_nothrow_swappable : public bool_constant<is_nothrow_swappable_v<_Tp>>
{};

// Do not use this trait over is_nothrow_swappable unless necessary. It is only useful in rare
// cases where a type may need to work with incomplete types and has friend functions that
// greedily instantiate the nothrow_swappable functions.
template <class _Tp, bool = __is_complete_v<_Tp>>
inline constexpr bool __is_complete_and_nothrow_swappable_v = false;

template <class _Tp>
inline constexpr bool __is_complete_and_nothrow_swappable_v<_Tp, true> = is_nothrow_swappable_v<_Tp>;

_CCCL_END_NAMESPACE_CUDA_STD

#include <cuda/std/__cccl/epilogue.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ struct BlowsUpOnConstCopy
{
static_assert(!cuda::std::is_same<T, T>::value, "");
}
BlowsUpOnConstCopy(BlowsUpOnConstCopy&) = default;
BlowsUpOnConstCopy(BlowsUpOnConstCopy&) = default;
BlowsUpOnConstCopy(BlowsUpOnConstCopy&&) = default;
};

// Test the following constructors:
Expand Down
2 changes: 1 addition & 1 deletion thrust/testing/swap_ranges.cu
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ struct type_with_swap
bool m_swapped;
};

inline _CCCL_HOST_DEVICE void swap(type_with_swap& a, type_with_swap& b)
inline _CCCL_HOST_DEVICE void swap(type_with_swap& a, type_with_swap& b) noexcept
{
using ::cuda::std::swap;
swap(a.m_x, b.m_x);
Expand Down
22 changes: 21 additions & 1 deletion thrust/thrust/detail/contiguous_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <cuda/std/__host_stdlib/stdexcept>
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__memory/allocator_traits.h>
#include <cuda/std/__type_traits/is_swappable.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__utility/swap.h>

Expand Down Expand Up @@ -100,8 +101,27 @@ class contiguous_storage

_CCCL_HOST_DEVICE void deallocate() noexcept;

private:
static constexpr bool is_swap_noexcept()
{
if (!::cuda::std::is_nothrow_swappable_v<iterator>)
{
return false;
}
if (!::cuda::std::is_nothrow_swappable_v<size_type>)
{
return false;
}
if (::cuda::std::allocator_traits<Alloc>::propagate_on_container_swap::value)
{
return ::cuda::std::is_nothrow_swappable_v<allocator_type>;
}
return ::cuda::std::allocator_traits<Alloc>::is_always_equal::value;
}

public:
_CCCL_EXEC_CHECK_DISABLE
_CCCL_HOST_DEVICE void swap(contiguous_storage& other)
_CCCL_HOST_DEVICE void swap(contiguous_storage& other) noexcept(is_swap_noexcept())
{
using ::cuda::std::swap;
swap(m_begin, other.m_begin);
Expand Down
4 changes: 3 additions & 1 deletion thrust/thrust/detail/vector_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <cuda/std/__iterator/iterator_traits.h>
#include <cuda/std/__iterator/reverse_iterator.h>
#include <cuda/std/__type_traits/enable_if.h>
#include <cuda/std/__type_traits/is_swappable.h>
#include <cuda/std/__utility/move.h>
#include <cuda/std/__utility/swap.h>
#include <cuda/std/initializer_list>
Expand Down Expand Up @@ -427,7 +428,8 @@ class vector_base
/*! This method swaps the contents of this vector_base with another vector_base.
* \param v The vector_base with which to swap.
*/
void swap(vector_base& v)
void swap(vector_base& v) noexcept(::cuda::std::is_nothrow_swappable_v<storage_type>
&& ::cuda::std::is_nothrow_swappable_v<size_type>)
{
using ::cuda::std::swap;
swap(m_storage, v.m_storage);
Expand Down
Loading