xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__config.hpp (revision 10d0b4b7d1498cfd5c3d37edea271a54d1984e41)
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