From f4b6bc99a87c6b70370e049b1c23e4a6007d27e7 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Tue, 9 Jun 2026 10:59:22 +0200 Subject: [PATCH 1/2] [libcu++] Always treat user passed types as values not sequences --- libcudacxx/include/cuda/__argument/argument.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcudacxx/include/cuda/__argument/argument.h b/libcudacxx/include/cuda/__argument/argument.h index 8741451b1d4..eaf93acbc89 100644 --- a/libcudacxx/include/cuda/__argument/argument.h +++ b/libcudacxx/include/cuda/__argument/argument.h @@ -547,7 +547,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 = true; static constexpr element_type lowest = ::cuda::std::numeric_limits::lowest(); static constexpr element_type highest = (::cuda::std::numeric_limits::max)(); }; From d0863c9e28cf5d24dbe9b99d0066634a73da227c Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Tue, 9 Jun 2026 11:00:09 +0200 Subject: [PATCH 2/2] [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 | 29 ++++++------ .../cuda/argument/argument_traits.pass.cpp | 44 +++++++++++-------- .../cuda/argument/dynamic_argument.pass.cpp | 2 +- .../cuda/argument/static_argument.pass.cpp | 2 +- .../cuda/argument/usage_example.pass.cpp | 2 + 5 files changed, 43 insertions(+), 36 deletions(-) diff --git a/libcudacxx/include/cuda/__argument/argument.h b/libcudacxx/include/cuda/__argument/argument.h index eaf93acbc89..a1d55db5045 100644 --- a/libcudacxx/include/cuda/__argument/argument.h +++ b/libcudacxx/include/cuda/__argument/argument.h @@ -25,8 +25,11 @@ #include #include #include +#include #include +#include #include +#include #include #include #include @@ -75,23 +78,13 @@ 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>) + || ::cuda::std::__has_random_access_traversal<_Tp>; // ===================================================================== // __constant @@ -121,7 +114,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 sequence"); [[nodiscard]] _CCCL_API static constexpr value_type value() noexcept { @@ -208,7 +201,11 @@ 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 (::cuda::std::__has_random_access_traversal<_Arg>) + { // FIXME: (miscco) This is broken. we do not know the size of the sequence + } + else if constexpr (__is_sequence_v<_Arg> && !::cuda::std::__has_random_access_traversal<_Arg> + && ::cuda::std::is_arithmetic_v<__element_type>) { for (const auto& __a : __arg_) { @@ -584,7 +581,7 @@ struct __traits_impl<__constant_sequence<_Value>> { 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 sequence"); static constexpr bool is_constant = true; static constexpr bool is_deferred = false; static constexpr bool is_single_value = false; diff --git a/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp index cdcc6665747..13753040f08 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp @@ -11,11 +11,17 @@ #include #include #include +#include +#include #include #include +#include #include +#include #include +#include +#include "test_iterators.h" #include "test_macros.h" enum class color @@ -50,32 +56,34 @@ 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>); + + // iterators and pointers can be sequences if they are at least random access 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>); + + // 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 +114,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); diff --git a/libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp b/libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp index e3a752b780a..8cc239585ac 100644 --- a/libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp +++ b/libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp @@ -82,6 +82,7 @@ TEST_FUNC constexpr bool test() assert(process_segments(100) == 100); } +#if 0 // FIXME(miscco): This should not work // Plain span: per-segment, no bounds, global memory { int sizes[3] = {64, 128, 96}; @@ -90,6 +91,7 @@ TEST_FUNC constexpr bool test() assert(compute_buffer_size(seg, 3) == default_max_segment_size * 3); assert(process_segments(seg) == 64 + 128 + 96); } +#endif // static_argument: scalar, fits in shared memory, buffer = value {