From f13ff250a89da6bae7e336f74c8f3f19aecde1fb Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 5 Jun 2026 09:17:49 +0200 Subject: [PATCH] [libcu++] Fix `__is_sequence` definition for arguments framework The current is_sequence definition is thoroughly broken. An iterator is not a sequence and neither is a pointer. The main problem here is that this precludes passing along iterators / pointers as values which is a reasonable use case. It also completely deviates from any standard handling in C++. Rather than reinventing the wheel in a bad way use standard terminology to determine what is a range and what not. A user can always wrap iterators and pointers into views and spans, so there is not need for the current definition --- libcudacxx/include/cuda/__argument/argument.h | 23 +++------- .../cuda/argument/argument_traits.pass.cpp | 45 ++++++++++--------- .../cuda/argument/dynamic_argument.pass.cpp | 2 +- .../cuda/argument/static_argument.pass.cpp | 2 +- 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/libcudacxx/include/cuda/__argument/argument.h b/libcudacxx/include/cuda/__argument/argument.h index fb514d22648..697b580ca53 100644 --- a/libcudacxx/include/cuda/__argument/argument.h +++ b/libcudacxx/include/cuda/__argument/argument.h @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -75,23 +77,12 @@ template using __element_type_of_t = typename __element_type_of<::cuda::std::remove_cvref_t<_Tp>>::type; // ===================================================================== -// __is_sequence_v / __is_single_value_v +// __is_sequence_v // ===================================================================== template inline constexpr bool __is_sequence_v = - !::cuda::std::is_same_v<::cuda::std::remove_cvref_t<_Tp>, __element_type_of_t<_Tp>>; - -template -inline constexpr bool __is_single_value_v = !__is_sequence_v<_Tp>; - -template -inline constexpr bool __is_iterable_v = false; - -template -inline constexpr bool __is_iterable_v<_Tp, - ::cuda::std::void_t().begin()), - decltype(::cuda::std::declval().end())>> = true; + ::cuda::std::is_array_v<::cuda::std::remove_cvref_t<_Tp>> || ::cuda::std::ranges::range<_Tp>; // ===================================================================== // __constant @@ -121,7 +112,7 @@ struct __constant_sequence using value_type = ::cuda::std::remove_cvref_t; using __element_type = __element_type_of_t; - static_assert(__is_sequence_v, "constant sequence arguments must have a distinct element type"); + static_assert(__is_sequence_v, "The value type of __constant_sequence must be a range or an array"); [[nodiscard]] _CCCL_API static constexpr value_type value() noexcept { @@ -332,7 +323,7 @@ struct __immediate_sequence _CCCL_API constexpr void __validate_value() const noexcept { - if constexpr (__is_iterable_v<_Arg> && ::cuda::std::is_arithmetic_v<__element_type>) + if constexpr (__is_sequence_v<_Arg> && ::cuda::std::is_arithmetic_v<__element_type>) { for (const auto& __a : __arg_) { @@ -671,7 +662,7 @@ struct __traits_impl using element_type = __element_type_of_t<_Tp>; static constexpr bool is_constant = false; static constexpr bool is_deferred = false; - static constexpr bool is_single_value = __is_single_value_v<_Tp>; + static constexpr bool is_single_value = !__is_sequence_v<_Tp>; static constexpr element_type lowest = ::cuda::std::numeric_limits::lowest(); static constexpr element_type highest = (::cuda::std::numeric_limits::max)(); }; diff --git a/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp index cdcc6665747..36154ef2207 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp @@ -11,10 +11,15 @@ #include #include #include +#include +#include #include #include +#include #include +#include #include +#include #include "test_macros.h" @@ -50,32 +55,32 @@ TEST_FUNC void test() { // --- __is_sequence_v / __is_single_value_v --- + // builtin and class type are not sequences static_assert(!cuda::__argument::__is_sequence_v); static_assert(!cuda::__argument::__is_sequence_v); static_assert(!cuda::__argument::__is_sequence_v); - static_assert(cuda::__argument::__is_sequence_v); - static_assert(cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + static_assert(!cuda::__argument::__is_sequence_v>); + + // iterators are not sequences and need to be wrapped into a range + static_assert(!cuda::__argument::__is_sequence_v); + static_assert(!cuda::__argument::__is_sequence_v>); + + // ranges and arrays are sequences + static_assert(cuda::__argument::__is_sequence_v); + static_assert(cuda::__argument::__is_sequence_v); + static_assert(cuda::__argument::__is_sequence_v); + static_assert(cuda::__argument::__is_sequence_v); static_assert(cuda::__argument::__is_sequence_v>); static_assert(cuda::__argument::__is_sequence_v&>); static_assert(cuda::__argument::__is_sequence_v>); static_assert(cuda::__argument::__is_sequence_v>); - static_assert(cuda::__argument::__is_sequence_v>); - static_assert(cuda::__argument::__is_sequence_v>); - static_assert(cuda::__argument::__is_sequence_v>); - - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(cuda::__argument::__is_single_value_v); - static_assert(!cuda::__argument::__is_single_value_v); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v&>); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v>); - static_assert(!cuda::__argument::__is_single_value_v>); // --- __element_type_of_t --- @@ -106,7 +111,7 @@ TEST_FUNC void test() // --- argument_traits: is_single_value --- static_assert(cuda::__argument::__traits::is_single_value); - static_assert(!cuda::__argument::__traits::is_single_value); + static_assert(cuda::__argument::__traits::is_single_value); static_assert(cuda::__argument::__traits>::is_single_value); static_assert(cuda::__argument::__traits>::is_single_value); static_assert( diff --git a/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp index eac5e71aa82..c9723304774 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp @@ -128,7 +128,7 @@ TEST_FUNC constexpr bool test() // __is_single_value_v on unwrapped types { static_assert( - cuda::__argument::__is_single_value_v>::value_type>); + !cuda::__argument::__is_sequence_v>::value_type>); static_assert( !cuda::__argument::__traits>>::is_single_value); } diff --git a/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp index 7d40183070b..85ccaf1c8a0 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp @@ -113,7 +113,7 @@ TEST_FUNC void test() // Single value: scalar is single, sequence is not { static_assert( - cuda::__argument::__is_single_value_v>::value_type>); + !cuda::__argument::__is_sequence_v>::value_type>); #if TEST_HAS_CLASS_NTTP static_assert(!cuda::__argument::__traits< cuda::__argument::__constant_sequence{1, 2, 3}>>::is_single_value);