From d74e7648a3531988aa0e77a8b11f7b2d6545c191 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 30 Apr 2026 10:05:52 -0700 Subject: [PATCH 1/2] extend the concept portability macros to support `_Convertible_to(T)` and `_Derived_from(T)` --- libcudacxx/include/cuda/__algorithm/common.h | 10 +-- .../cuda/std/__concepts/concept_macros.h | 66 +++++++++++++++---- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/libcudacxx/include/cuda/__algorithm/common.h b/libcudacxx/include/cuda/__algorithm/common.h index a0e21ad98d4..420d69a7676 100644 --- a/libcudacxx/include/cuda/__algorithm/common.h +++ b/libcudacxx/include/cuda/__algorithm/common.h @@ -38,9 +38,9 @@ using __as_span_t = ::cuda::std::span<::cuda::std::remove_reference_t<::cuda::st //! @brief A concept that checks if the type can be converted to a `cuda::std::span`. //! The type must be a contiguous range. template -_CCCL_CONCEPT __spannable = _CCCL_REQUIRES_EXPR((_Tp))( // - requires(::cuda::std::ranges::contiguous_range<_Tp>), // - requires(::cuda::std::convertible_to<_Tp, __as_span_t<_Tp>>)); +_CCCL_CONCEPT __spannable = _CCCL_REQUIRES_EXPR((_Tp), _Tp&& __value)( // + _Satisfies(::cuda::std::ranges::contiguous_range)::cuda::std::forward<_Tp>(__value), // + _Convertible_to(__as_span_t<_Tp>)::cuda::std::forward<_Tp>(__value)); template using __as_mdspan_t = @@ -52,8 +52,8 @@ using __as_mdspan_t = //! @brief A concept that checks if the type can be converted to a `cuda::std::mdspan`. //! The type must have a conversion to `__as_mdspan_t<_Tp>`. template -_CCCL_CONCEPT __mdspannable = - _CCCL_REQUIRES_EXPR((_Tp))(requires(::cuda::std::convertible_to<_Tp, __as_mdspan_t<_Tp>>)); +_CCCL_CONCEPT __mdspannable = _CCCL_REQUIRES_EXPR((_Tp), _Tp&& __value)( // + _Convertible_to(__as_mdspan_t<_Tp>)::cuda::std::forward<_Tp>(__value)); template [[nodiscard]] _CCCL_HOST_API constexpr auto __as_mdspan(_Tp&& __value) noexcept -> __as_mdspan_t<_Tp> diff --git a/libcudacxx/include/cuda/std/__concepts/concept_macros.h b/libcudacxx/include/cuda/std/__concepts/concept_macros.h index bcf594eca36..124ac392ac6 100644 --- a/libcudacxx/include/cuda/std/__concepts/concept_macros.h +++ b/libcudacxx/include/cuda/std/__concepts/concept_macros.h @@ -149,11 +149,13 @@ namespace __cccl_unqualified_cuda_std = ::cuda::std; // NOLINT(misc-unused-alias // - _Satisfies(CONCEPT...) EXPR... // // The last 4 are handled below: -#define _CCCL_CONCEPT_REQUIREMENT_SWITCH_requires _CCCL_PP_CASE(REQUIRES) -#define _CCCL_CONCEPT_REQUIREMENT_SWITCH_noexcept _CCCL_PP_CASE(NOEXCEPT) -#define _CCCL_CONCEPT_REQUIREMENT_SWITCH_typename _CCCL_PP_CASE(TYPENAME) -#define _CCCL_CONCEPT_REQUIREMENT_SWITCH__Same_as _CCCL_PP_CASE(SAME_AS) -#define _CCCL_CONCEPT_REQUIREMENT_SWITCH__Satisfies _CCCL_PP_CASE(SATISFIES) +#define _CCCL_CONCEPT_REQUIREMENT_SWITCH_requires _CCCL_PP_CASE(REQUIRES) +#define _CCCL_CONCEPT_REQUIREMENT_SWITCH_noexcept _CCCL_PP_CASE(NOEXCEPT) +#define _CCCL_CONCEPT_REQUIREMENT_SWITCH_typename _CCCL_PP_CASE(TYPENAME) +#define _CCCL_CONCEPT_REQUIREMENT_SWITCH__Same_as _CCCL_PP_CASE(SAME_AS) +#define _CCCL_CONCEPT_REQUIREMENT_SWITCH__Satisfies _CCCL_PP_CASE(SATISFIES) +#define _CCCL_CONCEPT_REQUIREMENT_SWITCH__Convertible_to _CCCL_PP_CASE(CONVERTIBLE_TO) +#define _CCCL_CONCEPT_REQUIREMENT_SWITCH__Derived_from _CCCL_PP_CASE(DERIVED_FROM) // Converts "requires(ARGS...)" to "ARGS..." #define _CCCL_CONCEPT_EAT_REQUIRES_(...) _CCCL_PP_CAT(_CCCL_CONCEPT_EAT_REQUIRES_, __VA_ARGS__) @@ -184,18 +186,42 @@ namespace __cccl_unqualified_cuda_std = ::cuda::std; // NOLINT(misc-unused-alias _CCCL_PP_CAT(_CCCL, _CCCL_PP_EVAL(_CCCL_PP_FIRST, _CCCL_PP_CAT(_CCCL_CONCEPT_GET_TYPE_FROM_SAME_AS_, __VA_ARGS__))) #define _CCCL_CONCEPT_GET_TYPE_FROM_SAME_AS__Same_as(...) _PP_EXPAND(__VA_ARGS__), -// Converts "_Satisfies(TYPE) EXPR..." to "EXPR..." +// Converts "_Satisfies(CONCEPT) EXPR..." to "EXPR..." #define _CCCL_CONCEPT_EAT_SATISFIES_(...) _CCCL_PP_CAT(_CCCL_CONCEPT_EAT_SATISFIES_, __VA_ARGS__) #define _CCCL_CONCEPT_EAT_SATISFIES__Satisfies(...) -// Converts "_Satisfies(TYPE) EXPR..." to "TYPE" (The ridiculous concatenation of _CCCL -// with _PP_EXPAND(__VA_ARGS__) is the only way to get MSVC's broken preprocessor to do macro -// expansion here.) +// Converts "_Satisfies(CONCEPT) EXPR..." to "CONCEPT" (The ridiculous concatenation of +// _CCCL with _PP_EXPAND(__VA_ARGS__) is the only way to get MSVC's broken preprocessor to +// do macro expansion here.) #define _CCCL_CONCEPT_GET_CONCEPT_FROM_SATISFIES_(...) \ _CCCL_PP_CAT(_CCCL, \ _CCCL_PP_EVAL(_CCCL_PP_FIRST, _CCCL_PP_CAT(_CCCL_CONCEPT_GET_CONCEPT_FROM_SATISFIES_, __VA_ARGS__))) #define _CCCL_CONCEPT_GET_CONCEPT_FROM_SATISFIES__Satisfies(...) _PP_EXPAND(__VA_ARGS__), +// Converts "_Convertible_to(TYPE) EXPR..." to "EXPR..." +#define _CCCL_CONCEPT_EAT_CONVERTIBLE_TO_(...) _CCCL_PP_CAT(_CCCL_CONCEPT_EAT_CONVERTIBLE_TO_, __VA_ARGS__) +#define _CCCL_CONCEPT_EAT_CONVERTIBLE_TO__Convertible_to(...) + +// Converts "_Convertible_to(TYPE) EXPR..." to "TYPE" (The ridiculous concatenation of +// _CCCL with _PP_EXPAND(__VA_ARGS__) is the only way to get MSVC's broken preprocessor to +// do macro expansion here.) +#define _CCCL_CONCEPT_GET_TYPE_FROM_CONVERTIBLE_TO_(...) \ + _CCCL_PP_CAT(_CCCL, \ + _CCCL_PP_EVAL(_CCCL_PP_FIRST, _CCCL_PP_CAT(_CCCL_CONCEPT_GET_TYPE_FROM_CONVERTIBLE_TO_, __VA_ARGS__))) +#define _CCCL_CONCEPT_GET_TYPE_FROM_CONVERTIBLE_TO__Convertible_to(...) _PP_EXPAND(__VA_ARGS__), + +// Converts "_Derived_from(TYPE) EXPR..." to "EXPR..." +#define _CCCL_CONCEPT_EAT_DERIVED_FROM_(...) _CCCL_PP_CAT(_CCCL_CONCEPT_EAT_DERIVED_FROM_, __VA_ARGS__) +#define _CCCL_CONCEPT_EAT_DERIVED_FROM__Derived_from(...) + +// Converts "_Derived_from(TYPE) EXPR..." to "TYPE" (The ridiculous concatenation of +// _CCCL with _PP_EXPAND(__VA_ARGS__) is the only way to get MSVC's broken preprocessor to +// do macro expansion here.) +#define _CCCL_CONCEPT_GET_TYPE_FROM_DERIVED_FROM_(...) \ + _CCCL_PP_CAT(_CCCL, \ + _CCCL_PP_EVAL(_CCCL_PP_FIRST, _CCCL_PP_CAT(_CCCL_CONCEPT_GET_TYPE_FROM_DERIVED_FROM_, __VA_ARGS__))) +#define _CCCL_CONCEPT_GET_TYPE_FROM_DERIVED_FROM__Derived_from(...) _PP_EXPAND(__VA_ARGS__), + // Here are the implementations of the internal macros, first for when concepts // are available, and then for when they're not. #if _CCCL_HAS_CONCEPTS() || defined(_CCCL_DOXYGEN_INVOKED) @@ -222,6 +248,12 @@ namespace __cccl_unqualified_cuda_std = ::cuda::std; // NOLINT(misc-unused-alias {_CCCL_CONCEPT_EAT_SAME_AS_(_REQ)}->_CCCL_CONCEPT_VSTD::same_as<_CCCL_CONCEPT_GET_TYPE_FROM_SAME_AS_(_REQ)> # define _CCCL_CONCEPT_REQUIREMENT_CASE_SATISFIES(_REQ) \ {_CCCL_CONCEPT_EAT_SATISFIES_(_REQ)}->_CCCL_CONCEPT_GET_CONCEPT_FROM_SATISFIES_(_REQ) +# define _CCCL_CONCEPT_REQUIREMENT_CASE_CONVERTIBLE_TO(_REQ) \ + {_CCCL_CONCEPT_EAT_CONVERTIBLE_TO_(_REQ)} \ + ->_CCCL_CONCEPT_VSTD::convertible_to<_CCCL_CONCEPT_GET_TYPE_FROM_CONVERTIBLE_TO_(_REQ)> +# define _CCCL_CONCEPT_REQUIREMENT_CASE_DERIVED_FROM(_REQ) \ + {_CCCL_CONCEPT_EAT_DERIVED_FROM_(_REQ)} \ + ->_CCCL_CONCEPT_VSTD::derived_from<_CCCL_CONCEPT_GET_TYPE_FROM_DERIVED_FROM_(_REQ)> # define _CCCL_FRAGMENT(_NAME, ...) _NAME<__VA_ARGS__> @@ -269,10 +301,22 @@ namespace __cccl_unqualified_cuda_std = ::cuda::std; // NOLINT(misc-unused-alias # define _CCCL_CONCEPT_REQUIREMENT_CASE_SATISFIES(_REQ) \ ::__cccl_requires < _CCCL_CONCEPT_GET_CONCEPT_FROM_SATISFIES_(_REQ) < decltype(_CCCL_CONCEPT_EAT_SATISFIES_(_REQ)) \ >> +# define _CCCL_CONCEPT_REQUIREMENT_CASE_CONVERTIBLE_TO(_REQ) \ + ::__cccl_requires<::cuda::std::convertible_to<_CCCL_CONCEPT_CONVERTIBLE_TO_REQUIREMENT_(_REQ)>> +# define _CCCL_CONCEPT_REQUIREMENT_CASE_DERIVED_FROM(_REQ) \ + ::__cccl_requires<::cuda::std::derived_from<_CCCL_CONCEPT_DERIVED_FROM_REQUIREMENT_(_REQ)>> -// Converts "_Same_as(TYPE) EXPR..." to "TYPE, decltype(EXPR...)" +// Converts "_Same_as(TYPE) EXPR..." to "decltype(EXPR...), TYPE" # define _CCCL_CONCEPT_SAME_AS_REQUIREMENT_(_REQ) \ - _CCCL_CONCEPT_GET_TYPE_FROM_SAME_AS_(_REQ), decltype(_CCCL_CONCEPT_EAT_SAME_AS_(_REQ)) + decltype(_CCCL_CONCEPT_EAT_SAME_AS_(_REQ)), _CCCL_CONCEPT_GET_TYPE_FROM_SAME_AS_(_REQ) + +// Converts "_Convertible_to(TYPE) EXPR..." to "decltype(EXPR...), TYPE" +# define _CCCL_CONCEPT_CONVERTIBLE_TO_REQUIREMENT_(_REQ) \ + decltype(_CCCL_CONCEPT_EAT_CONVERTIBLE_TO_(_REQ)), _CCCL_CONCEPT_GET_TYPE_FROM_CONVERTIBLE_TO_(_REQ) + +// Converts "_Derived_from(TYPE) EXPR..." to "decltype(EXPR...), TYPE" +# define _CCCL_CONCEPT_DERIVED_FROM_REQUIREMENT_(_REQ) \ + decltype(_CCCL_CONCEPT_EAT_DERIVED_FROM_(_REQ)), _CCCL_CONCEPT_GET_TYPE_FROM_DERIVED_FROM_(_REQ) # if _CCCL_HAS_NOEXCEPT_MANGLING() // Converts "noexcept(EXPR)" to "::__cccl_requires" From 804f9945867968e0d14f37be95b97c6f462bf79a Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 30 Apr 2026 12:21:39 -0700 Subject: [PATCH 2/2] avoid nvcc-12.0 concepts parsing bug --- libcudacxx/include/cuda/__algorithm/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcudacxx/include/cuda/__algorithm/common.h b/libcudacxx/include/cuda/__algorithm/common.h index 420d69a7676..6429ad48276 100644 --- a/libcudacxx/include/cuda/__algorithm/common.h +++ b/libcudacxx/include/cuda/__algorithm/common.h @@ -39,7 +39,7 @@ using __as_span_t = ::cuda::std::span<::cuda::std::remove_reference_t<::cuda::st //! The type must be a contiguous range. template _CCCL_CONCEPT __spannable = _CCCL_REQUIRES_EXPR((_Tp), _Tp&& __value)( // - _Satisfies(::cuda::std::ranges::contiguous_range)::cuda::std::forward<_Tp>(__value), // + _Satisfies(cuda::std::ranges::contiguous_range)::cuda::std::forward<_Tp>(__value), // _Convertible_to(__as_span_t<_Tp>)::cuda::std::forward<_Tp>(__value)); template