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 #if __cplusplus < 202002L
19 #if defined(_MSC_VER) && !defined(__clang__)
20 #    error This library requires the use of C++20. Use /Zc:__cplusplus to enable __cplusplus conformance.
21 #else
22 #error This library requires the use of C++20.
23 #endif
24 #endif
25 
26 #if defined(_MSC_VER) && !defined(__clang__) &&                                \
27     (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL)
28 #  error This library requires the use of the new conforming preprocessor enabled by /Zc:preprocessor.
29 #endif
30 
31 #if __has_include(<version>)
32 #include <version>
33 #else
34 #include <ciso646> // For stdlib feature-test macros when <version> is not available
35 #endif
36 
37 #include <cassert>
38 #include <type_traits>
39 
40 #define STDEXEC_STRINGIZE(_ARG) #_ARG
41 
42 #define STDEXEC_CAT_(_XP, ...) _XP##__VA_ARGS__
43 #define STDEXEC_CAT(_XP, ...) STDEXEC_CAT_(_XP, __VA_ARGS__)
44 
45 #define STDEXEC_EXPAND(...) __VA_ARGS__
46 #define STDEXEC_EVAL(_MACRO, ...) _MACRO(__VA_ARGS__)
47 #define STDEXEC_EAT(...)
48 
49 #define STDEXEC_IIF(_XP, _YP, ...)                                             \
50     STDEXEC_IIF_EVAL(STDEXEC_CAT(STDEXEC_IIF_, _XP), _YP, __VA_ARGS__)
51 #define STDEXEC_IIF_0(_YP, ...) __VA_ARGS__
52 #define STDEXEC_IIF_1(_YP, ...) _YP
53 #define STDEXEC_IIF_EVAL(_MACRO, ...) _MACRO(__VA_ARGS__)
54 
55 #define STDEXEC_COMPL(_B) STDEXEC_COMPL_CAT(STDEXEC_COMPL_, _B)
56 #define STDEXEC_COMPL_0 1
57 #define STDEXEC_COMPL_1 0
58 #define STDEXEC_COMPL_CAT(_XP, ...) _XP##__VA_ARGS__
59 
60 #define STDEXEC_COUNT(...)                                                     \
61     STDEXEC_EXPAND(STDEXEC_COUNT_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
62 #define STDEXEC_COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _NP, ...) _NP
63 
64 #define STDEXEC_CHECK(...) STDEXEC_EXPAND(STDEXEC_CHECK_(__VA_ARGS__, 0, ))
65 #define STDEXEC_CHECK_(_XP, _NP, ...) _NP
66 #define STDEXEC_PROBE(...) STDEXEC_PROBE_(__VA_ARGS__, 1)
67 #define STDEXEC_PROBE_(_XP, _NP, ...) _XP, _NP,
68 
69 #define STDEXEC_NOT(_XP) STDEXEC_CHECK(STDEXEC_CAT(STDEXEC_NOT_, _XP))
70 #define STDEXEC_NOT_0 STDEXEC_PROBE(~, 1)
71 
72 #define STDEXEC_BOOL(_XP) STDEXEC_COMPL(STDEXEC_NOT(_XP))
73 #define STDEXEC_IF(_XP, _YP, ...)                                              \
74     STDEXEC_IIF(STDEXEC_BOOL(_XP), _YP, __VA_ARGS__)
75 
76 #define STDEXEC_WHEN(_XP, ...)                                                 \
77     STDEXEC_IF(_XP, STDEXEC_EXPAND, STDEXEC_EAT)(__VA_ARGS__)
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 // STDEXEC_FOR_EACH
81 //   Inspired by "Recursive macros with C++20 __VA_OPT__", by David Mazières
82 //   https://www.scs.stanford.edu/~dm/blog/va-opt.html
83 #define STDEXEC_EXPAND_R(...)                                                  \
84     STDEXEC_EXPAND_R1(                                                         \
85         STDEXEC_EXPAND_R1(STDEXEC_EXPAND_R1(STDEXEC_EXPAND_R1(__VA_ARGS__))))  \
86     /**/
87 #define STDEXEC_EXPAND_R1(...)                                                 \
88     STDEXEC_EXPAND_R2(                                                         \
89         STDEXEC_EXPAND_R2(STDEXEC_EXPAND_R2(STDEXEC_EXPAND_R2(__VA_ARGS__))))  \
90     /**/
91 #define STDEXEC_EXPAND_R2(...)                                                 \
92     STDEXEC_EXPAND_R3(                                                         \
93         STDEXEC_EXPAND_R3(STDEXEC_EXPAND_R3(STDEXEC_EXPAND_R3(__VA_ARGS__))))  \
94     /**/
95 #define STDEXEC_EXPAND_R3(...)                                                 \
96     STDEXEC_EXPAND(                                                            \
97         STDEXEC_EXPAND(STDEXEC_EXPAND(STDEXEC_EXPAND(__VA_ARGS__))))           \
98     /**/
99 
100 #define STDEXEC_PARENS ()
101 #define STDEXEC_FOR_EACH(_MACRO, ...)                                          \
102     __VA_OPT__(STDEXEC_EXPAND_R(STDEXEC_FOR_EACH_HELPER(_MACRO, __VA_ARGS__))) \
103     /**/
104 #define STDEXEC_FOR_EACH_HELPER(_MACRO, _A1, ...)                              \
105     _MACRO(_A1)                                                                \
106     __VA_OPT__(STDEXEC_FOR_EACH_AGAIN STDEXEC_PARENS(_MACRO, __VA_ARGS__)) /**/
107 #define STDEXEC_FOR_EACH_AGAIN() STDEXEC_FOR_EACH_HELPER
108 ////////////////////////////////////////////////////////////////////////////////////////////////////
109 
110 #define STDEXEC_FRONT(...) __VA_OPT__(STDEXEC_FRONT_HELPER(__VA_ARGS__))
111 #define STDEXEC_FRONT_HELPER(_A1, ...) _A1
112 #define STDEXEC_BACK(...)                                                      \
113     __VA_OPT__(STDEXEC_EXPAND_R(STDEXEC_BACK_HELPER(__VA_ARGS__)))
114 #define STDEXEC_BACK_HELPER(_A1, ...)                                          \
115     STDEXEC_FRONT(__VA_OPT__(, ) _A1, )                                        \
116     __VA_OPT__(STDEXEC_BACK_AGAIN STDEXEC_PARENS(__VA_ARGS__))
117 #define STDEXEC_BACK_AGAIN() STDEXEC_BACK_HELPER
118 
119 // If tail is non-empty, expand to the tail. Otherwise, expand to the head
120 #define STDEXEC_HEAD_OR_TAIL(_XP, ...)                                         \
121     STDEXEC_EXPAND __VA_OPT__((__VA_ARGS__)STDEXEC_EAT)(_XP)
122 
123 // If tail is non-empty, expand to nothing. Otherwise, expand to the head
124 #define STDEXEC_HEAD_OR_NULL(_XP, ...)                                         \
125     STDEXEC_EXPAND __VA_OPT__(() STDEXEC_EAT)(_XP)
126 
127 // When used with no arguments, these macros expand to 1 if the current
128 // compiler corresponds to the macro name; 0, otherwise. When used with
129 // arguments, they expand to the arguments if if the current compiler
130 // corresponds to the macro name; nothing, otherwise.
131 #if defined(__NVCC__)
132 #define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
133 #elif defined(__NVCOMPILER)
134 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
135 #elif defined(__EDG__)
136 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
137 #elif defined(__clang__)
138 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
139 #if defined(_MSC_VER)
140 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
141 #endif
142 #if defined(__apple_build_version__)
143 #define STDEXEC_APPLE_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
144 #endif
145 #elif defined(__GNUC__)
146 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
147 #elif defined(_MSC_VER)
148 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
149 #endif
150 
151 #ifndef STDEXEC_NVCC
152 #define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
153 #endif
154 #ifndef STDEXEC_NVHPC
155 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
156 #endif
157 #ifndef STDEXEC_EDG
158 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
159 #endif
160 #ifndef STDEXEC_CLANG
161 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
162 #endif
163 #ifndef STDEXEC_CLANG_CL
164 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
165 #endif
166 #ifndef STDEXEC_APPLE_CLANG
167 #define STDEXEC_APPLE_CLANG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
168 #endif
169 #ifndef STDEXEC_GCC
170 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
171 #endif
172 #ifndef STDEXEC_MSVC
173 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
174 #endif
175 
176 #if STDEXEC_NVHPC()
177 #define STDEXEC_NVHPC_VERSION()                                                \
178     (__NVCOMPILER_MAJOR__ * 100 + __NVCOMPILER_MINOR__)
179 #endif
180 
181 ////////////////////////////////////////////////////////////////////////////////////////////////////
182 #ifdef __CUDACC__
183 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
184 #else
185 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
186 #endif
187 
188 ////////////////////////////////////////////////////////////////////////////////////////////////////
189 #if __cpp_impl_coroutine >= 201902 && __cpp_lib_coroutine >= 201902
190 #include <coroutine>
191 #define STDEXEC_STD_NO_COROUTINES() 0
192 namespace __coro = std;
193 #elif defined(__cpp_coroutines) && __has_include(<experimental/coroutine>)
194 #include <experimental/coroutine>
195 #define STDEXEC_STD_NO_COROUTINES() 0
196 namespace __coro = std::experimental;
197 #else
198 #define STDEXEC_STD_NO_COROUTINES() 1
199 #endif
200 
201 ////////////////////////////////////////////////////////////////////////////////////////////////////
202 // For portably declaring attributes on functions and types
203 //   Usage:
204 //
205 //   STDEXEC_ATTRIBUTE((attr1, attr2, ...))
206 //   void foo() { ... }
207 #define STDEXEC_ATTRIBUTE(_XP)                                                 \
208     STDEXEC_FOR_EACH(STDEXEC_ATTR, STDEXEC_EXPAND _XP)
209 #define STDEXEC_ATTR(_ATTR)                                                    \
210     STDEXEC_CAT(STDEXEC_ATTR_WHICH_,                                           \
211                 STDEXEC_CHECK(STDEXEC_CAT(STDEXEC_ATTR_, _ATTR)))              \
212     (_ATTR)
213 
214 // unknown attributes are treated like C++-style attributes
215 #define STDEXEC_ATTR_WHICH_0(_ATTR) [[_ATTR]]
216 
217 // custom handling for specific attribute types
218 #ifdef __CUDACC__
219 #define STDEXEC_ATTR_WHICH_1(_ATTR) __host__
220 #else
221 #define STDEXEC_ATTR_WHICH_1(_ATTR)
222 #endif
223 #define STDEXEC_ATTR_host STDEXEC_PROBE(~, 1)
224 #define STDEXEC_ATTR___host__ STDEXEC_PROBE(~, 1)
225 
226 #ifdef __CUDACC__
227 #define STDEXEC_ATTR_WHICH_2(_ATTR) __device__
228 #else
229 #define STDEXEC_ATTR_WHICH_2(_ATTR)
230 #endif
231 #define STDEXEC_ATTR_device STDEXEC_PROBE(~, 2)
232 #define STDEXEC_ATTR___device__ STDEXEC_PROBE(~, 2)
233 
234 #if STDEXEC_NVHPC()
235 // NVBUG #4067067: NVHPC does not fully support [[no_unique_address]]
236 #define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/
237 #elif STDEXEC_MSVC()
238 // MSVCBUG
239 // https://developercommunity.visualstudio.com/t/Incorrect-codegen-when-using-msvc::no_/10452874
240 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]]
241 #elif STDEXEC_CLANG_CL()
242 // clang-cl does not support: https://reviews.llvm.org/D110485
243 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]]
244 #else
245 #define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]]
246 #endif
247 #define STDEXEC_ATTR_no_unique_address STDEXEC_PROBE(~, 3)
248 
249 #if STDEXEC_MSVC()
250 #define STDEXEC_ATTR_WHICH_4(_ATTR) __forceinline
251 #elif STDEXEC_CLANG()
252 #define STDEXEC_ATTR_WHICH_4(_ATTR)                                            \
253     __attribute__((__always_inline__, __artificial__, __nodebug__)) inline
254 #elif defined(__GNUC__)
255 #define STDEXEC_ATTR_WHICH_4(_ATTR)                                            \
256     __attribute__((__always_inline__, __artificial__)) inline
257 #else
258 #define STDEXEC_ATTR_WHICH_4(_ATTR) /*nothing*/
259 #endif
260 #define STDEXEC_ATTR_always_inline STDEXEC_PROBE(~, 4)
261 
262 #if STDEXEC_CLANG() || STDEXEC_GCC()
263 #define STDEXEC_ATTR_WHICH_5(_ATTR) __attribute__((__weak__))
264 #else
265 #define STDEXEC_ATTR_WHICH_5(_ATTR) /*nothing*/
266 #endif
267 #define STDEXEC_ATTR_weak STDEXEC_PROBE(~, 5)
268 #define STDEXEC_ATTR___weak__ STDEXEC_PROBE(~, 5)
269 
270 ////////////////////////////////////////////////////////////////////////////////////////////////////
271 // warning push/pop portability macros
272 #if STDEXEC_NVCC()
273 #define STDEXEC_PRAGMA_PUSH() _Pragma("nv_diagnostic push")
274 #define STDEXEC_PRAGMA_POP() _Pragma("nv_diagnostic pop")
275 #define STDEXEC_PRAGMA_IGNORE_EDG(...)                                         \
276     _Pragma(STDEXEC_STRINGIZE(nv_diag_suppress __VA_ARGS__))
277 #elif STDEXEC_NVHPC() || STDEXEC_EDG()
278 #define STDEXEC_PRAGMA_PUSH()                                                  \
279     _Pragma("diagnostic push") STDEXEC_PRAGMA_IGNORE_EDG(invalid_error_number)
280 #define STDEXEC_PRAGMA_POP() _Pragma("diagnostic pop")
281 #define STDEXEC_PRAGMA_IGNORE_EDG(...)                                         \
282     _Pragma(STDEXEC_STRINGIZE(diag_suppress __VA_ARGS__))
283 #elif STDEXEC_CLANG() || STDEXEC_GCC()
284 #define STDEXEC_PRAGMA_PUSH()                                                  \
285     _Pragma("GCC diagnostic push") STDEXEC_PRAGMA_IGNORE_GNU("-Wpragmas")      \
286         STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-pragmas")                         \
287             STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-warning-option")              \
288                 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-attributes")              \
289                     STDEXEC_PRAGMA_IGNORE_GNU("-Wattributes")
290 #define STDEXEC_PRAGMA_POP() _Pragma("GCC diagnostic pop")
291 #define STDEXEC_PRAGMA_IGNORE_GNU(...)                                         \
292     _Pragma(STDEXEC_STRINGIZE(GCC diagnostic ignored __VA_ARGS__))
293 #elif STDEXEC_MSVC()
294 #define STDEXEC_PRAGMA_PUSH() __pragma(warning(push))
295 #define STDEXEC_PRAGMA_POP() __pragma(warning(pop))
296 #define STDEXEC_PRAGMA_IGNORE_MSVC(...) __pragma(warning(disable : __VA_ARGS__))
297 #else
298 #define STDEXEC_PRAGMA_PUSH()
299 #define STDEXEC_PRAGMA_POP()
300 #endif
301 
302 #ifndef STDEXEC_PRAGMA_IGNORE_GNU
303 #define STDEXEC_PRAGMA_IGNORE_GNU(...)
304 #endif
305 #ifndef STDEXEC_PRAGMA_IGNORE_EDG
306 #define STDEXEC_PRAGMA_IGNORE_EDG(...)
307 #endif
308 #ifndef STDEXEC_PRAGMA_IGNORE_MSVC
309 #define STDEXEC_PRAGMA_IGNORE_MSVC(...)
310 #endif
311 
312 #if !STDEXEC_MSVC() && defined(__has_builtin)
313 #define STDEXEC_HAS_BUILTIN __has_builtin
314 #else
315 #define STDEXEC_HAS_BUILTIN(...) 0
316 #endif
317 
318 #if !STDEXEC_MSVC() && defined(__has_feature)
319 #define STDEXEC_HAS_FEATURE __has_feature
320 #else
321 #define STDEXEC_HAS_FEATURE(...) 0
322 #endif
323 
324 #if STDEXEC_HAS_BUILTIN(__is_trivially_copyable) || STDEXEC_MSVC()
325 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...) __is_trivially_copyable(__VA_ARGS__)
326 #else
327 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...)                                     \
328     std::is_trivially_copyable_v<__VA_ARGS__>
329 #endif
330 
331 #if STDEXEC_HAS_BUILTIN(__is_base_of) || (_MSC_VER >= 1914)
332 #define STDEXEC_IS_BASE_OF(...) __is_base_of(__VA_ARGS__)
333 #else
334 #define STDEXEC_IS_BASE_OF(...) std::is_base_of_v<__VA_ARGS__>
335 #endif
336 
337 #if STDEXEC_HAS_BUILTIN(__is_convertible_to) || STDEXEC_MSVC()
338 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible_to(__VA_ARGS__)
339 #elif STDEXEC_HAS_BUILTIN(__is_convertible)
340 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible(__VA_ARGS__)
341 #else
342 #define STDEXEC_IS_CONVERTIBLE_TO(...) std::is_convertible_v<__VA_ARGS__>
343 #endif
344 
345 #if STDEXEC_HAS_BUILTIN(__is_const)
346 #define STDEXEC_IS_CONST(...) __is_const(__VA_ARGS__)
347 #else
348 #define STDEXEC_IS_CONST(...) stdexec::__is_const_<__VA_ARGS__>
349 #endif
350 
351 #if STDEXEC_HAS_BUILTIN(__is_same)
352 #define STDEXEC_IS_SAME(...) __is_same(__VA_ARGS__)
353 #elif STDEXEC_HAS_BUILTIN(__is_same_as)
354 #define STDEXEC_IS_SAME(...) __is_same_as(__VA_ARGS__)
355 #elif STDEXEC_MSVC()
356 // msvc replaces std::is_same_v with a compile-time constant
357 #define STDEXEC_IS_SAME(...) std::is_same_v<__VA_ARGS__>
358 #else
359 #define STDEXEC_IS_SAME(...) stdexec::__same_as_v<__VA_ARGS__>
360 #endif
361 
362 #if STDEXEC_HAS_BUILTIN(__is_constructible) || STDEXEC_MSVC()
363 #define STDEXEC_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__)
364 #else
365 #define STDEXEC_IS_CONSTRUCTIBLE(...) std::is_constructible_v<__VA_ARGS__>
366 #endif
367 
368 #if STDEXEC_HAS_BUILTIN(__is_nothrow_constructible) || STDEXEC_MSVC()
369 #define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...)                                  \
370     __is_nothrow_constructible(__VA_ARGS__)
371 #else
372 #define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...)                                  \
373     std::is_nothrow_constructible_v<__VA_ARGS__>
374 #endif
375 
376 #if STDEXEC_HAS_BUILTIN(__is_trivially_constructible) || STDEXEC_MSVC()
377 #define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...)                                \
378     __is_trivially_constructible(__VA_ARGS__)
379 #else
380 #define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...)                                \
381     std::is_trivially_constructible_v<__VA_ARGS__>
382 #endif
383 
384 #if STDEXEC_HAS_BUILTIN(__is_empty) || STDEXEC_MSVC()
385 #define STDEXEC_IS_EMPTY(...) __is_empty(__VA_ARGS__)
386 #else
387 #define STDEXEC_IS_EMPTY(...) std::is_empty_v<__VA_ARGS__>
388 #endif
389 
390 #if STDEXEC_HAS_BUILTIN(__remove_reference)
391 namespace stdexec
392 {
393 template <class Ty>
394 using _remove_reference_t = __remove_reference(Ty);
395 } // namespace stdexec
396 
397 #define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__>
398 #elif STDEXEC_HAS_BUILTIN(__remove_reference_t)
399 namespace stdexec
400 {
401 template <class Ty>
402 using _remove_reference_t = __remove_reference_t(Ty);
403 } // namespace stdexec
404 
405 #define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__>
406 #else
407 #define STDEXEC_REMOVE_REFERENCE(...) ::std::remove_reference_t<__VA_ARGS__>
408 #endif
409 
410 namespace stdexec
411 {
412 template <class _Ap, class _Bp>
413 inline constexpr bool __same_as_v = false;
414 
415 template <class _Ap>
416 inline constexpr bool __same_as_v<_Ap, _Ap> = true;
417 } // namespace stdexec
418 
419 #if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
420 #define STDEXEC_UNREACHABLE() std::unreachable()
421 #elif STDEXEC_HAS_BUILTIN(__builtin_unreachable)
422 #define STDEXEC_UNREACHABLE() __builtin_unreachable()
423 #elif STDEXEC_MSVC()
424 #define STDEXEC_UNREACHABLE(...) __assume(false)
425 #else
426 #define STDEXEC_UNREACHABLE(...) std::terminate()
427 #endif
428 
429 // Before gcc-12, gcc really didn't like tuples or variants of immovable types
430 #if STDEXEC_GCC() && (__GNUC__ < 12)
431 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&)
432 #else
433 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) = delete
434 #endif
435 
436 // BUG (gcc PR93711): copy elision fails when initializing a
437 // [[no_unique_address]] field from a function returning an object
438 // of class type by value
439 #if STDEXEC_GCC()
440 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
441 #else
442 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS                                    \
443     STDEXEC_ATTRIBUTE((no_unique_address))
444 #endif
445 
446 #if STDEXEC_NVHPC()
447 #include <nv/target>
448 #define STDEXEC_TERMINATE()                                                    \
449     NV_IF_TARGET(NV_IS_HOST, (std::terminate();), (__trap();)) void()
450 #elif STDEXEC_CLANG() && STDEXEC_CUDA() && defined(__CUDA_ARCH__)
451 #define STDEXEC_TERMINATE()                                                    \
452     __trap();                                                                  \
453     __builtin_unreachable()
454 #else
455 #define STDEXEC_TERMINATE() std::terminate()
456 #endif
457 
458 #if STDEXEC_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__)
459 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
460 #else
461 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
462 #endif
463 
464 // Before clang-16, clang did not like libstdc++'s ranges implementation
465 #if __has_include(<ranges>) && \
466   (defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L) && \
467   (!STDEXEC_CLANG() || __clang_major__ >= 16 || defined(_LIBCPP_VERSION))
468 #define STDEXEC_HAS_STD_RANGES() 1
469 #else
470 #define STDEXEC_HAS_STD_RANGES() 0
471 #endif
472 
473 #if __has_include(<memory_resource>) && \
474   (defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L)
475 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 1
476 #else
477 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 0
478 #endif
479 
480 #ifdef STDEXEC_ASSERT
481 #error                                                                         \
482     "Redefinition of STDEXEC_ASSERT is not permitted. Define STDEXEC_ASSERT_FN instead."
483 #endif
484 
485 #define STDEXEC_ASSERT(_XP)                                                    \
486     do                                                                         \
487     {                                                                          \
488         static_assert(noexcept(_XP));                                          \
489         STDEXEC_ASSERT_FN(_XP);                                                \
490     } while (false)
491 
492 #ifndef STDEXEC_ASSERT_FN
493 #define STDEXEC_ASSERT_FN assert
494 #endif
495 
496 #define STDEXEC_AUTO_RETURN(...)                                               \
497     noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__)                     \
498     {                                                                          \
499         return __VA_ARGS__;                                                    \
500     }
501 
502 // GCC 13 implements lexical friendship, but it is incomplete. See
503 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111018
504 #if STDEXEC_CLANG() // || (STDEXEC_GCC() && __GNUC__ >= 13)
505 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 1
506 #else
507 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 0
508 #endif
509 
510 #if defined(__cpp_explicit_this_parameter) &&                                  \
511     (__cpp_explicit_this_parameter >= 202110)
512 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
513 #else
514 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
515 #endif
516 
517 // Configure extra type checking
518 #define STDEXEC_TYPE_CHECKING_ZERO() 0
519 #define STDEXEC_TYPE_CHECKING_ONE() 1
520 #define STDEXEC_TYPE_CHECKING_TWO() 2
521 
522 #define STDEXEC_PROBE_TYPE_CHECKING_ STDEXEC_TYPE_CHECKING_ONE
523 #define STDEXEC_PROBE_TYPE_CHECKING_0 STDEXEC_TYPE_CHECKING_ZERO
524 #define STDEXEC_PROBE_TYPE_CHECKING_1 STDEXEC_TYPE_CHECKING_ONE
525 #define STDEXEC_PROBE_TYPE_CHECKING_STDEXEC_ENABLE_EXTRA_TYPE_CHECKING         \
526     STDEXEC_TYPE_CHECKING_TWO
527 
528 #define STDEXEC_TYPE_CHECKING_WHICH3(...)                                      \
529     STDEXEC_PROBE_TYPE_CHECKING_##__VA_ARGS__
530 #define STDEXEC_TYPE_CHECKING_WHICH2(...)                                      \
531     STDEXEC_TYPE_CHECKING_WHICH3(__VA_ARGS__)
532 #define STDEXEC_TYPE_CHECKING_WHICH                                            \
533     STDEXEC_TYPE_CHECKING_WHICH2(STDEXEC_ENABLE_EXTRA_TYPE_CHECKING)
534 
535 #ifndef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
536 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0
537 #elif STDEXEC_TYPE_CHECKING_WHICH() == 2
538 // do nothing
539 #elif STDEXEC_TYPE_CHECKING_WHICH() == 0
540 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
541 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0
542 #else
543 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
544 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 1
545 #endif
546 
547 namespace stdexec
548 {}
549