1 /* 2 * Copyright (c) 2022 NVIDIA Corporation 3 * 4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * https://llvm.org/LICENSE.txt 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 // IWYU pragma: always_keep 19 20 #if __cplusplus < 2020'02L 21 # if defined(_MSC_VER) && !defined(__clang__) 22 # error This library requires the use of C++20. Use /Zc:__cplusplus to enable __cplusplus conformance. 23 # else 24 # error This library requires the use of C++20. 25 # endif 26 #endif 27 28 #if defined(_MSC_VER) && !defined(__clang__) && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL) 29 # error This library requires the use of the new conforming preprocessor enabled by /Zc:preprocessor. 30 #endif 31 32 #include "__preprocessor.hpp" 33 34 #if __has_include(<version>) 35 # include <version> 36 #else 37 # include <ciso646> // For stdlib feature-test macros when <version> is not available 38 #endif 39 40 #include <cassert> 41 #include <cstdlib> 42 #include <type_traits> // IWYU pragma: keep 43 #include <utility> // IWYU pragma: keep for std::unreachable 44 45 // When used with no arguments, these macros expand to 1 if the current 46 // compiler corresponds to the macro name; 0, otherwise. When used with arguments, 47 // they expand to the arguments if if the current compiler corresponds to the 48 // macro name; nothing, otherwise. 49 #if defined(__NVCC__) 50 # define STDEXEC_NVCC() 1 51 # define STDEXEC_NVCC_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) 52 #elif defined(__EDG__) 53 # define STDEXEC_EDG() 1 54 # define STDEXEC_EDG_VERSION __EDG_VERSION__ 55 # if defined(__NVCOMPILER) 56 # define STDEXEC_NVHPC() 1 57 # define STDEXEC_NVHPC_VERSION (__NVCOMPILER_MAJOR__ * 100 + __NVCOMPILER_MINOR__) 58 # endif 59 # if defined(__INTELLISENSE__) 60 # define STDEXEC_INTELLISENSE() 1 61 # define STDEXEC_MSVC_HEADERS() 1 62 # endif 63 #elif defined(__clang__) 64 # define STDEXEC_CLANG() 1 65 # define STDEXEC_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) 66 # if defined(_MSC_VER) 67 # define STDEXEC_CLANG_CL() 1 68 # endif 69 # if defined(__apple_build_version__) 70 # define STDEXEC_APPLE_CLANG() 1 71 // Apple clang version is encoded as major * 1000000 + minor * 1000 + patch. We ignore the patch 72 // version here, as it is not relevant for the purposes of this library. 73 # define STDEXEC_APPLE_CLANG_VERSION (__apple_build_version__ / 1000) 74 # endif 75 #elif defined(__GNUC__) 76 # define STDEXEC_GCC() 1 77 # define STDEXEC_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) 78 #elif defined(_MSC_VER) 79 # define STDEXEC_MSVC() 1 80 # define STDEXEC_MSVC_HEADERS() 1 81 # define STDEXEC_MSVC_VERSION _MSC_VER 82 #endif 83 84 #ifndef STDEXEC_NVCC 85 # define STDEXEC_NVCC() 0 86 #endif 87 #ifndef STDEXEC_NVHPC 88 # define STDEXEC_NVHPC() 0 89 #endif 90 #ifndef STDEXEC_EDG 91 # define STDEXEC_EDG() 0 92 #endif 93 #ifndef STDEXEC_CLANG 94 # define STDEXEC_CLANG() 0 95 #endif 96 #ifndef STDEXEC_CLANG_CL 97 # define STDEXEC_CLANG_CL() 0 98 #endif 99 #ifndef STDEXEC_APPLE_CLANG 100 # define STDEXEC_APPLE_CLANG() 0 101 #endif 102 #ifndef STDEXEC_GCC 103 # define STDEXEC_GCC() 0 104 #endif 105 #ifndef STDEXEC_MSVC 106 # define STDEXEC_MSVC() 0 107 #endif 108 #ifndef STDEXEC_MSVC_HEADERS 109 # define STDEXEC_MSVC_HEADERS() 0 110 #endif 111 #ifndef STDEXEC_INTELLISENSE 112 # define STDEXEC_INTELLISENSE() 0 113 #endif 114 115 //////////////////////////////////////////////////////////////////////////////////////////////////// 116 #if defined(__CUDACC__) || STDEXEC_NVHPC() 117 # define STDEXEC_CUDA_COMPILATION() 1 118 #else 119 # define STDEXEC_CUDA_COMPILATION() 0 120 #endif 121 122 //////////////////////////////////////////////////////////////////////////////////////////////////// 123 #if defined(__has_attribute) 124 # define STDEXEC_HAS_ATTRIBUTE(...) __has_attribute(__VA_ARGS__) 125 #else 126 # define STDEXEC_HAS_ATTRIBUTE(...) 0 127 #endif 128 129 //////////////////////////////////////////////////////////////////////////////////////////////////// 130 #if STDEXEC_CLANG() && STDEXEC_CUDA_COMPILATION() 131 # define STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE __host__ __device__ 132 #else 133 # define STDEXEC_HOST_DEVICE_DEDUCTION_GUIDE 134 #endif 135 136 //////////////////////////////////////////////////////////////////////////////////////////////////// 137 #if __cpp_impl_coroutine >= 2019'02 && __cpp_lib_coroutine >= 2019'02 138 # include <coroutine> // IWYU pragma: keep 139 # define STDEXEC_STD_NO_COROUTINES() 0 140 namespace __coro = std; // NOLINT(misc-unused-alias-decls) 141 #elif defined(__cpp_coroutines) && __has_include(<experimental/coroutine>) 142 # include <experimental/coroutine> 143 # define STDEXEC_STD_NO_COROUTINES() 0 144 namespace __coro = std::experimental; 145 #else 146 # define STDEXEC_STD_NO_COROUTINES() 1 147 #endif 148 149 //////////////////////////////////////////////////////////////////////////////////////////////////// 150 // For portably declaring attributes on functions and types 151 // Usage: 152 // 153 // STDEXEC_ATTRIBUTE(attr1, attr2, ...) 154 // void foo() { ... } 155 #define STDEXEC_ATTRIBUTE(...) STDEXEC_FOR_EACH(STDEXEC__ATTRIBUTE_DETAIL, __VA_ARGS__) 156 #define STDEXEC__ATTRIBUTE_DETAIL(_ATTR) \ 157 STDEXEC_CAT(STDEXEC_ATTR_WHICH_, STDEXEC_CHECK(STDEXEC_CAT(STDEXEC_ATTR_, _ATTR)))(_ATTR) 158 159 // unknown attributes are treated like C++-style attributes 160 #define STDEXEC_ATTR_WHICH_0(_ATTR) [[_ATTR]] 161 162 // custom handling for specific attribute types 163 #ifdef __CUDACC__ 164 # define STDEXEC_ATTR_WHICH_1(_ATTR) __host__ 165 #else 166 # define STDEXEC_ATTR_WHICH_1(_ATTR) 167 #endif 168 #define STDEXEC_ATTR_host STDEXEC_PROBE(~, 1) 169 #define STDEXEC_ATTR___host__ STDEXEC_PROBE(~, 1) 170 171 #ifdef __CUDACC__ 172 # define STDEXEC_ATTR_WHICH_2(_ATTR) __device__ 173 #else 174 # define STDEXEC_ATTR_WHICH_2(_ATTR) 175 #endif 176 #define STDEXEC_ATTR_device STDEXEC_PROBE(~, 2) 177 #define STDEXEC_ATTR___device__ STDEXEC_PROBE(~, 2) 178 179 #if STDEXEC_NVHPC() 180 // NVBUG #4067067: NVHPC does not fully support [[no_unique_address]] 181 # if STDEXEC_NVHPC_VERSION < 23'05 182 # define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/ 183 # else 184 # define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]] 185 # endif 186 #elif STDEXEC_CLANG_CL() 187 // clang-cl does not support [[no_unique_address]]: https://reviews.llvm.org/D110485 188 // TODO: Find the version that started supporting [[msvc::no_unique_address]] 189 # if STDEXEC_CLANG_VERSION < 18'01 190 # define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/ 191 # else 192 # define STDEXEC_ATTR_WHICH_3(_ATTR) [[msvc::no_unique_address]] 193 # endif 194 #elif STDEXEC_MSVC() 195 // MSVCBUG https://developercommunity.visualstudio.com/t/Incorrect-codegen-when-using-msvc::no_/10452874 196 # if STDEXEC_MSVC_VERSION < 19'43 197 # define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/ 198 # else 199 # define STDEXEC_ATTR_WHICH_3(_ATTR) [[msvc::no_unique_address]] 200 # endif 201 #else 202 # define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]] 203 #endif 204 #define STDEXEC_ATTR_no_unique_address STDEXEC_PROBE(~, 3) 205 206 #if STDEXEC_MSVC() 207 # define STDEXEC_ATTR_WHICH_4(_ATTR) __forceinline 208 #elif STDEXEC_CLANG() 209 # define STDEXEC_ATTR_WHICH_4(_ATTR) \ 210 __attribute__((__always_inline__, __artificial__, __nodebug__)) inline 211 #elif STDEXEC_GCC() 212 # define STDEXEC_ATTR_WHICH_4(_ATTR) __attribute__((__always_inline__, __artificial__)) inline 213 #else 214 # define STDEXEC_ATTR_WHICH_4(_ATTR) /*nothing*/ 215 #endif 216 #define STDEXEC_ATTR_always_inline STDEXEC_PROBE(~, 4) 217 218 #if STDEXEC_CLANG() || STDEXEC_GCC() 219 # define STDEXEC_ATTR_WHICH_5(_ATTR) __attribute__((__weak__)) 220 #else 221 # define STDEXEC_ATTR_WHICH_5(_ATTR) /*nothing*/ 222 #endif 223 #define STDEXEC_ATTR_weak STDEXEC_PROBE(~, 5) 224 #define STDEXEC_ATTR___weak__ STDEXEC_PROBE(~, 5) 225 226 #if STDEXEC_HAS_ATTRIBUTE(__preferred_name__) 227 # define STDEXEC_ATTR_WHICH_6(_ATTR) __attribute__((_ATTR)) 228 #else 229 # define STDEXEC_ATTR_WHICH_6(_ATTR) /*nothing*/ 230 #endif 231 #define STDEXEC_ATTR_preferred_name STDEXEC_PROBE(~, 6) 232 #define STDEXEC_ATTR___preferred_name__ STDEXEC_PROBE(~, 6) 233 234 //////////////////////////////////////////////////////////////////////////////////////////////////// 235 // warning push/pop portability macros 236 #if STDEXEC_NVCC() 237 # define STDEXEC_PRAGMA_PUSH() _Pragma("nv_diagnostic push") 238 # define STDEXEC_PRAGMA_POP() _Pragma("nv_diagnostic pop") 239 # define STDEXEC_PRAGMA_IGNORE_EDG(...) _Pragma(STDEXEC_STRINGIZE(nv_diag_suppress __VA_ARGS__)) 240 #elif STDEXEC_EDG() 241 # define STDEXEC_PRAGMA_PUSH() \ 242 _Pragma("diagnostic push") STDEXEC_PRAGMA_IGNORE_EDG(invalid_error_number) \ 243 STDEXEC_PRAGMA_IGNORE_EDG(invalid_error_tag) 244 # define STDEXEC_PRAGMA_POP() _Pragma("diagnostic pop") 245 # define STDEXEC_PRAGMA_IGNORE_EDG(...) _Pragma(STDEXEC_STRINGIZE(diag_suppress __VA_ARGS__)) 246 #elif STDEXEC_CLANG() || STDEXEC_GCC() 247 # define STDEXEC_PRAGMA_PUSH() \ 248 _Pragma("GCC diagnostic push") STDEXEC_PRAGMA_IGNORE_GNU("-Wpragmas") \ 249 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-pragmas") \ 250 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-warning-option") \ 251 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-attributes") \ 252 STDEXEC_PRAGMA_IGNORE_GNU("-Wattributes") 253 # define STDEXEC_PRAGMA_POP() _Pragma("GCC diagnostic pop") 254 # define STDEXEC_PRAGMA_IGNORE_GNU(...) \ 255 _Pragma(STDEXEC_STRINGIZE(GCC diagnostic ignored __VA_ARGS__)) 256 #elif STDEXEC_MSVC() 257 # define STDEXEC_PRAGMA_PUSH() __pragma(warning(push)) 258 # define STDEXEC_PRAGMA_POP() __pragma(warning(pop)) 259 # define STDEXEC_PRAGMA_IGNORE_MSVC(...) __pragma(warning(disable : __VA_ARGS__)) 260 #else 261 # define STDEXEC_PRAGMA_PUSH() 262 # define STDEXEC_PRAGMA_POP() 263 #endif 264 265 #ifndef STDEXEC_PRAGMA_IGNORE_GNU 266 # define STDEXEC_PRAGMA_IGNORE_GNU(...) 267 #endif 268 #ifndef STDEXEC_PRAGMA_IGNORE_EDG 269 # define STDEXEC_PRAGMA_IGNORE_EDG(...) 270 #endif 271 #ifndef STDEXEC_PRAGMA_IGNORE_MSVC 272 # define STDEXEC_PRAGMA_IGNORE_MSVC(...) 273 #endif 274 275 #if !STDEXEC_MSVC() && defined(__has_builtin) 276 # define STDEXEC_HAS_BUILTIN __has_builtin 277 #else 278 # define STDEXEC_HAS_BUILTIN(...) 0 279 #endif 280 281 #if !STDEXEC_MSVC() && defined(__has_feature) 282 # define STDEXEC_HAS_FEATURE __has_feature 283 #else 284 # define STDEXEC_HAS_FEATURE(...) 0 285 #endif 286 287 #if STDEXEC_HAS_BUILTIN(__is_trivially_copyable) || STDEXEC_MSVC() 288 # define STDEXEC_IS_TRIVIALLY_COPYABLE(...) __is_trivially_copyable(__VA_ARGS__) 289 #else 290 # define STDEXEC_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable_v<__VA_ARGS__> 291 #endif 292 293 #if STDEXEC_HAS_BUILTIN(__is_base_of) || (STDEXEC_MSVC_VERSION >= 19'14) 294 # define STDEXEC_IS_BASE_OF(...) __is_base_of(__VA_ARGS__) 295 #else 296 # define STDEXEC_IS_BASE_OF(...) std::is_base_of_v<__VA_ARGS__> 297 #endif 298 299 #if STDEXEC_HAS_BUILTIN(__is_convertible_to) || STDEXEC_MSVC() 300 # define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible_to(__VA_ARGS__) 301 #elif STDEXEC_HAS_BUILTIN(__is_convertible) 302 # define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible(__VA_ARGS__) 303 #else 304 # define STDEXEC_IS_CONVERTIBLE_TO(...) std::is_convertible_v<__VA_ARGS__> 305 #endif 306 307 #if STDEXEC_HAS_BUILTIN(__is_const) 308 # define STDEXEC_IS_CONST(...) __is_const(__VA_ARGS__) 309 #else 310 # define STDEXEC_IS_CONST(...) stdexec::__is_const_<__VA_ARGS__> 311 #endif 312 313 #if STDEXEC_HAS_BUILTIN(__is_function) 314 # define STDEXEC_IS_FUNCTION(...) __is_function(__VA_ARGS__) 315 #else 316 # define STDEXEC_IS_FUNCTION(...) \ 317 (!STDEXEC_IS_CONST(__VA_ARGS__) && !STDEXEC_IS_CONST(const __VA_ARGS__)) 318 #endif 319 320 #if STDEXEC_HAS_BUILTIN(__is_same) 321 # define STDEXEC_IS_SAME(...) __is_same(__VA_ARGS__) 322 #elif STDEXEC_HAS_BUILTIN(__is_same_as) 323 # define STDEXEC_IS_SAME(...) __is_same_as(__VA_ARGS__) 324 #elif STDEXEC_MSVC() 325 // msvc replaces std::is_same_v with a compile-time constant 326 # define STDEXEC_IS_SAME(...) std::is_same_v<__VA_ARGS__> 327 #else 328 # define STDEXEC_IS_SAME(...) stdexec::__same_as_v<__VA_ARGS__> 329 #endif 330 331 #if STDEXEC_HAS_BUILTIN(__is_constructible) || STDEXEC_MSVC() 332 # define STDEXEC_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__) 333 #else 334 # define STDEXEC_IS_CONSTRUCTIBLE(...) std::is_constructible_v<__VA_ARGS__> 335 #endif 336 337 #if STDEXEC_HAS_BUILTIN(__is_nothrow_constructible) || STDEXEC_MSVC() 338 # define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...) __is_nothrow_constructible(__VA_ARGS__) 339 #else 340 # define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...) std::is_nothrow_constructible_v<__VA_ARGS__> 341 #endif 342 343 #if STDEXEC_HAS_BUILTIN(__is_trivially_constructible) || STDEXEC_MSVC() 344 # define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...) __is_trivially_constructible(__VA_ARGS__) 345 #else 346 # define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...) std::is_trivially_constructible_v<__VA_ARGS__> 347 #endif 348 349 #if STDEXEC_HAS_BUILTIN(__is_empty) || STDEXEC_MSVC() 350 # define STDEXEC_IS_EMPTY(...) __is_empty(__VA_ARGS__) 351 #else 352 # define STDEXEC_IS_EMPTY(...) std::is_empty_v<__VA_ARGS__> 353 #endif 354 355 #if STDEXEC_HAS_BUILTIN(__remove_reference) 356 namespace stdexec { 357 template <class Ty> 358 using _remove_reference_t = __remove_reference(Ty); 359 } // namespace stdexec 360 361 # define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__> 362 #elif STDEXEC_HAS_BUILTIN(__remove_reference_t) 363 namespace stdexec { 364 template <class Ty> 365 using _remove_reference_t = __remove_reference_t(Ty); 366 } // namespace stdexec 367 368 # define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__> 369 #else 370 # define STDEXEC_REMOVE_REFERENCE(...) ::std::remove_reference_t<__VA_ARGS__> 371 #endif 372 373 namespace stdexec { 374 template <class _Ap, class _Bp> 375 inline constexpr bool __same_as_v = false; 376 377 template <class _Ap> 378 inline constexpr bool __same_as_v<_Ap, _Ap> = true; 379 } // namespace stdexec 380 381 #if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 2022'02L 382 # define STDEXEC_UNREACHABLE() std::unreachable() 383 #elif STDEXEC_HAS_BUILTIN(__builtin_unreachable) 384 # define STDEXEC_UNREACHABLE() __builtin_unreachable() 385 #elif STDEXEC_MSVC() 386 # define STDEXEC_UNREACHABLE(...) __assume(false) 387 #else 388 # define STDEXEC_UNREACHABLE(...) std::terminate() 389 #endif 390 391 // Before gcc-12, gcc really didn't like tuples or variants of immovable types 392 #if STDEXEC_GCC() && (STDEXEC_GCC_VERSION < 12'00) 393 # define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) 394 #else 395 # define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) = delete 396 #endif 397 398 #if STDEXEC_GCC() 399 // BUG (gcc#98995): copy elision fails when initializing a [[no_unique_address]] field 400 // from a function returning an object of class type by value. 401 // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98995 402 # define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS 403 #elif STDEXEC_CLANG() && (__clang_major__ >= 15 && __clang_major__ < 19) 404 // See https://github.com/llvm/llvm-project/issues/93563 405 # define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS 406 #else 407 # define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS STDEXEC_ATTRIBUTE(no_unique_address) 408 #endif 409 410 #if STDEXEC_NVHPC() 411 # include <nv/target> 412 # define STDEXEC_TERMINATE() NV_IF_TARGET(NV_IS_HOST, (std::terminate();), (__trap();)) void() 413 #elif STDEXEC_CLANG() && STDEXEC_CUDA_COMPILATION() && defined(__CUDA_ARCH__) 414 # define STDEXEC_TERMINATE() \ 415 __trap(); \ 416 __builtin_unreachable() 417 #else 418 # define STDEXEC_TERMINATE() std::terminate() 419 #endif 420 421 // Some compilers turn on pack indexing in pre-C++26 code. We want to use it if it is 422 // available. Pack indexing is disabled for clang < 20 because of: 423 // https://github.com/llvm/llvm-project/issues/116105 424 #if defined(__cpp_pack_indexing) && !STDEXEC_NVCC() \ 425 && !(STDEXEC_CLANG() && STDEXEC_CLANG_VERSION < 20'00) 426 # define STDEXEC_STD_NO_PACK_INDEXING() 0 427 #else // ^^^ has pack indexing ^^^ / vvv no pack indexing vvv 428 # define STDEXEC_STD_NO_PACK_INDEXING() 1 429 #endif // no pack indexing 430 431 #if STDEXEC_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) 432 # define STDEXEC_TSAN() 1 433 #else 434 # define STDEXEC_TSAN() 0 435 #endif 436 437 // Before clang-16, clang did not like libstdc++'s ranges implementation 438 #if __has_include(<ranges>) && \ 439 (defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 2019'11L) && \ 440 (!STDEXEC_CLANG() || STDEXEC_CLANG_VERSION >= 16'00 || defined(_LIBCPP_VERSION)) 441 # define STDEXEC_HAS_STD_RANGES() 1 442 #else 443 # define STDEXEC_HAS_STD_RANGES() 0 444 #endif 445 446 #if __has_include(<memory_resource>) && \ 447 (defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 2016'03L) 448 # define STDEXEC_HAS_STD_MEMORY_RESOURCE() 1 449 #else 450 # define STDEXEC_HAS_STD_MEMORY_RESOURCE() 0 451 #endif 452 453 #if defined(__cpp_lib_execution) && __cpp_lib_execution >= 2016'03L 454 # define STDEXEC_HAS_EXECUTION_POLICY() 1 455 #else 456 # define STDEXEC_HAS_EXECUTION_POLICY() 0 457 #endif 458 459 #if defined(__cpp_lib_execution) && __cpp_lib_execution >= 2019'02L 460 # define STDEXEC_HAS_UNSEQUENCED_EXECUTION_POLICY() 1 461 #else 462 # define STDEXEC_HAS_UNSEQUENCED_EXECUTION_POLICY() 0 463 #endif 464 465 #ifdef STDEXEC_ASSERT 466 # error "Redefinition of STDEXEC_ASSERT is not permitted. Define STDEXEC_ASSERT_FN instead." 467 #endif 468 469 #define STDEXEC_ASSERT(_XP) \ 470 do { \ 471 static_assert(noexcept(_XP)); \ 472 STDEXEC_ASSERT_FN(_XP); \ 473 } while (false) 474 475 #ifndef STDEXEC_ASSERT_FN 476 # define STDEXEC_ASSERT_FN assert 477 #endif 478 479 #define STDEXEC_AUTO_RETURN(...) \ 480 noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ 481 return __VA_ARGS__; \ 482 } 483 484 // GCC 13 implements lexical friendship, but it is incomplete. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111018 485 #if STDEXEC_CLANG() // || (STDEXEC_GCC() && STDEXEC_GCC_VERSION >= 13'00) 486 # define STDEXEC_FRIENDSHIP_IS_LEXICAL() 1 487 #else 488 # define STDEXEC_FRIENDSHIP_IS_LEXICAL() 0 489 #endif 490 491 #if defined(__cpp_explicit_this_parameter) && (__cpp_explicit_this_parameter >= 2021'10L) 492 # define STDEXEC_EXPLICIT_THIS() 1 493 #else 494 # define STDEXEC_EXPLICIT_THIS() 0 495 #endif 496 497 #if STDEXEC_ENABLE_EXTRA_TYPE_CHECKING == 0 498 # undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 499 # define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0 500 #else 501 # undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING 502 # define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 1 503 #endif 504 505 #if STDEXEC_CUDA_COMPILATION() && defined(__CUDA_ARCH__) 506 # define STDEXEC_STD_NO_EXCEPTIONS() 1 507 #elif STDEXEC_MSVC() || STDEXEC_CLANG_CL() 508 # define STDEXEC_STD_NO_EXCEPTIONS() (_HAS_EXCEPTIONS == 0) || (_CPPUNWIND == 0) 509 #else 510 # define STDEXEC_STD_NO_EXCEPTIONS() (__EXCEPTIONS == 0) 511 #endif 512 513 // We need to treat host and device separately 514 #if STDEXEC_CUDA_COMPILATION() && defined(__CUDA_ARCH__) && !STDEXEC_NVHPC() 515 # define STDEXEC_GLOBAL_CONSTANT STDEXEC_ATTRIBUTE(device) constexpr 516 #else 517 # define STDEXEC_GLOBAL_CONSTANT inline constexpr 518 #endif 519 520 #if STDEXEC_CUDA_COMPILATION() || __has_include(<cuda_runtime_api.h>) 521 # define STDEXEC_HAS_CTK() 1 522 #else 523 # define STDEXEC_HAS_CTK() 0 524 #endif 525 526 // clang-format off 527 #if STDEXEC_HAS_CTK() && __has_include(<nv/target>) 528 # include <nv/target> 529 # define STDEXEC_IF_HOST(...) NV_IF_TARGET(NV_IS_HOST, (__VA_ARGS__;)) 530 # define STDEXEC_IF_DEVICE(...) NV_IF_TARGET(NV_IS_DEVICE, (__VA_ARGS__;)) 531 #else 532 # define STDEXEC_IF_HOST(...) {__VA_ARGS__;} 533 # define STDEXEC_IF_DEVICE(...) 534 #endif 535 // clang-format on 536 537 // CUDA compilers preinclude cuda_runtime.h, but if we're not compiling for CUDA then we 538 // need to include it ourselves. 539 #if STDEXEC_HAS_CTK() && !STDEXEC_CUDA_COMPILATION() 540 # include <cuda_runtime_api.h> 541 #endif 542 543 // clang-format off 544 545 // The following macros are used to conditionally compile exception handling code. They 546 // are used in the same way as `try` and `catch`, but they allow for different behavior 547 // based on whether exceptions are enabled or not, and whether the code is being compiled 548 // for device or not. 549 // 550 // Usage: 551 // STDEXEC_TRY 552 // { 553 // can_throw(); // Code that may throw an exception 554 // } 555 // STDEXEC_CATCH (cuda_error& e) // Handle CUDA exceptions 556 // { 557 // printf("CUDA error: %s\n", e.what()); 558 // } 559 // STDEXEC_CATCH_ALL // Handle any other exceptions 560 // { 561 // printf("unknown error\n"); 562 // } 563 #if STDEXEC_STD_NO_EXCEPTIONS() 564 # define STDEXEC_TRY if constexpr (true) { 565 # define STDEXEC_CATCH(...) } else if constexpr (__VA_ARGS__ = ::stdexec::__catch_any_lvalue; false) { 566 # define STDEXEC_CATCH_ALL } else if constexpr (true) {} else 567 # define STDEXEC_THROW(...) ::stdexec::__terminate() 568 # define STDEXEC_CATCH_FALLTHROUGH } else {} 569 #else 570 # define STDEXEC_TRY try 571 # define STDEXEC_CATCH catch 572 # define STDEXEC_CATCH_ALL catch(...) 573 # define STDEXEC_THROW(...) throw __VA_ARGS__ 574 # define STDEXEC_CATCH_FALLTHROUGH 575 #endif 576 577 // clang-format on 578 579 namespace stdexec { 580 // Used by the STDEXEC_CATCH macro to provide a stub initialization of the exception object. 581 constexpr struct __catch_any_lvalue_t { 582 template <class _Tp> 583 STDEXEC_ATTRIBUTE(host, device) 584 operator _Tp&() const noexcept; 585 } __catch_any_lvalue{}; 586 STDEXEC_ATTRIBUTE(noreturn,host,device)587 STDEXEC_ATTRIBUTE(noreturn, host, device) 588 inline void __terminate() noexcept { 589 STDEXEC_IF_HOST(::exit(-1)) 590 STDEXEC_IF_DEVICE(__trap()) 591 STDEXEC_UNREACHABLE(); 592 } 593 } // namespace stdexec 594 595 //////////////////////////////////////////////////////////////////////////////////////////////////// 596 // clang-tidy struggles with the CUDA function annotations 597 #if STDEXEC_CLANG() && STDEXEC_CUDA_COMPILATION() && defined(STDEXEC_CLANG_TIDY_INVOKED) 598 # include <cuda_runtime_api.h> // IWYU pragma: keep 599 # if !defined(__launch_bounds__) 600 # define __launch_bounds__(...) 601 # endif 602 603 # if !defined(__host__) 604 # define __host__ 605 # endif 606 607 # if !defined(__device__) 608 # define __device__ 609 # endif 610 611 # if !defined(__global__) 612 # define __global__ 613 # endif 614 #endif 615 616 namespace stdexec { 617 } 618