xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/__detail/__config.hpp (revision f083bc1a64e1f94c99fc270b7c0856810f4be638)
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(__EDG__)
134 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
135 #if defined(__NVCOMPILER)
136 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
137 #endif
138 #if defined(__INTELLISENSE__)
139 #define STDEXEC_INTELLISENSE(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
140 #define STDEXEC_MSVC_HEADERS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
141 #endif
142 #elif defined(__clang__)
143 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
144 #if defined(_MSC_VER)
145 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
146 #endif
147 #if defined(__apple_build_version__)
148 #define STDEXEC_APPLE_CLANG(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
149 #endif
150 #elif defined(__GNUC__)
151 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
152 #elif defined(_MSC_VER)
153 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
154 #define STDEXEC_MSVC_HEADERS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
155 #endif
156 
157 #ifndef STDEXEC_NVCC
158 #define STDEXEC_NVCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
159 #endif
160 #ifndef STDEXEC_NVHPC
161 #define STDEXEC_NVHPC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
162 #endif
163 #ifndef STDEXEC_EDG
164 #define STDEXEC_EDG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
165 #endif
166 #ifndef STDEXEC_CLANG
167 #define STDEXEC_CLANG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
168 #endif
169 #ifndef STDEXEC_CLANG_CL
170 #define STDEXEC_CLANG_CL(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
171 #endif
172 #ifndef STDEXEC_APPLE_CLANG
173 #define STDEXEC_APPLE_CLANG(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
174 #endif
175 #ifndef STDEXEC_GCC
176 #define STDEXEC_GCC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
177 #endif
178 #ifndef STDEXEC_MSVC
179 #define STDEXEC_MSVC(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
180 #endif
181 #ifndef STDEXEC_MSVC_HEADERS
182 #define STDEXEC_MSVC_HEADERS(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
183 #endif
184 #ifndef STDEXEC_INTELLISENSE
185 #define STDEXEC_INTELLISENSE(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
186 #endif
187 
188 #if STDEXEC_NVHPC()
189 #define STDEXEC_NVHPC_VERSION()                                                \
190     (__NVCOMPILER_MAJOR__ * 100 + __NVCOMPILER_MINOR__)
191 #endif
192 
193 ////////////////////////////////////////////////////////////////////////////////////////////////////
194 #ifdef __CUDACC__
195 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
196 #else
197 #define STDEXEC_CUDA(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
198 #endif
199 
200 ////////////////////////////////////////////////////////////////////////////////////////////////////
201 #if __cpp_impl_coroutine >= 201902 && __cpp_lib_coroutine >= 201902
202 #include <coroutine>
203 #define STDEXEC_STD_NO_COROUTINES() 0
204 namespace __coro = std;
205 #elif defined(__cpp_coroutines) && __has_include(<experimental/coroutine>)
206 #include <experimental/coroutine>
207 #define STDEXEC_STD_NO_COROUTINES() 0
208 namespace __coro = std::experimental;
209 #else
210 #define STDEXEC_STD_NO_COROUTINES() 1
211 #endif
212 
213 ////////////////////////////////////////////////////////////////////////////////////////////////////
214 // For portably declaring attributes on functions and types
215 //   Usage:
216 //
217 //   STDEXEC_ATTRIBUTE((attr1, attr2, ...))
218 //   void foo() { ... }
219 #define STDEXEC_ATTRIBUTE(_XP)                                                 \
220     STDEXEC_FOR_EACH(STDEXEC_ATTR, STDEXEC_EXPAND _XP)
221 #define STDEXEC_ATTR(_ATTR)                                                    \
222     STDEXEC_CAT(STDEXEC_ATTR_WHICH_,                                           \
223                 STDEXEC_CHECK(STDEXEC_CAT(STDEXEC_ATTR_, _ATTR)))              \
224     (_ATTR)
225 
226 // unknown attributes are treated like C++-style attributes
227 #define STDEXEC_ATTR_WHICH_0(_ATTR) [[_ATTR]]
228 
229 // custom handling for specific attribute types
230 #ifdef __CUDACC__
231 #define STDEXEC_ATTR_WHICH_1(_ATTR) __host__
232 #else
233 #define STDEXEC_ATTR_WHICH_1(_ATTR)
234 #endif
235 #define STDEXEC_ATTR_host STDEXEC_PROBE(~, 1)
236 #define STDEXEC_ATTR___host__ STDEXEC_PROBE(~, 1)
237 
238 #ifdef __CUDACC__
239 #define STDEXEC_ATTR_WHICH_2(_ATTR) __device__
240 #else
241 #define STDEXEC_ATTR_WHICH_2(_ATTR)
242 #endif
243 #define STDEXEC_ATTR_device STDEXEC_PROBE(~, 2)
244 #define STDEXEC_ATTR___device__ STDEXEC_PROBE(~, 2)
245 
246 #if STDEXEC_NVHPC()
247 // NVBUG #4067067: NVHPC does not fully support [[no_unique_address]]
248 #define STDEXEC_ATTR_WHICH_3(_ATTR) /*nothing*/
249 #elif STDEXEC_MSVC()
250 // MSVCBUG
251 // https://developercommunity.visualstudio.com/t/Incorrect-codegen-when-using-msvc::no_/10452874
252 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]]
253 #elif STDEXEC_CLANG_CL()
254 // clang-cl does not support: https://reviews.llvm.org/D110485
255 #define STDEXEC_ATTR_WHICH_3(_ATTR) // [[msvc::no_unique_address]]
256 #else
257 #define STDEXEC_ATTR_WHICH_3(_ATTR) [[no_unique_address]]
258 #endif
259 #define STDEXEC_ATTR_no_unique_address STDEXEC_PROBE(~, 3)
260 
261 #if STDEXEC_MSVC()
262 #define STDEXEC_ATTR_WHICH_4(_ATTR) __forceinline
263 #elif STDEXEC_CLANG()
264 #define STDEXEC_ATTR_WHICH_4(_ATTR)                                            \
265     __attribute__((__always_inline__, __artificial__, __nodebug__)) inline
266 #elif defined(__GNUC__)
267 #define STDEXEC_ATTR_WHICH_4(_ATTR)                                            \
268     __attribute__((__always_inline__, __artificial__)) inline
269 #else
270 #define STDEXEC_ATTR_WHICH_4(_ATTR) /*nothing*/
271 #endif
272 #define STDEXEC_ATTR_always_inline STDEXEC_PROBE(~, 4)
273 
274 #if STDEXEC_CLANG() || STDEXEC_GCC()
275 #define STDEXEC_ATTR_WHICH_5(_ATTR) __attribute__((__weak__))
276 #else
277 #define STDEXEC_ATTR_WHICH_5(_ATTR) /*nothing*/
278 #endif
279 #define STDEXEC_ATTR_weak STDEXEC_PROBE(~, 5)
280 #define STDEXEC_ATTR___weak__ STDEXEC_PROBE(~, 5)
281 
282 ////////////////////////////////////////////////////////////////////////////////////////////////////
283 // warning push/pop portability macros
284 #if STDEXEC_NVCC()
285 #define STDEXEC_PRAGMA_PUSH() _Pragma("nv_diagnostic push")
286 #define STDEXEC_PRAGMA_POP() _Pragma("nv_diagnostic pop")
287 #define STDEXEC_PRAGMA_IGNORE_EDG(...)                                         \
288     _Pragma(STDEXEC_STRINGIZE(nv_diag_suppress __VA_ARGS__))
289 #elif STDEXEC_EDG()
290 #define STDEXEC_PRAGMA_PUSH()                                                  \
291     _Pragma("diagnostic push") STDEXEC_PRAGMA_IGNORE_EDG(invalid_error_number)
292 #define STDEXEC_PRAGMA_POP() _Pragma("diagnostic pop")
293 #define STDEXEC_PRAGMA_IGNORE_EDG(...)                                         \
294     _Pragma(STDEXEC_STRINGIZE(diag_suppress __VA_ARGS__))
295 #elif STDEXEC_CLANG() || STDEXEC_GCC()
296 #define STDEXEC_PRAGMA_PUSH()                                                  \
297     _Pragma("GCC diagnostic push") STDEXEC_PRAGMA_IGNORE_GNU("-Wpragmas")      \
298         STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-pragmas")                         \
299             STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-warning-option")              \
300                 STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-attributes")              \
301                     STDEXEC_PRAGMA_IGNORE_GNU("-Wattributes")
302 #define STDEXEC_PRAGMA_POP() _Pragma("GCC diagnostic pop")
303 #define STDEXEC_PRAGMA_IGNORE_GNU(...)                                         \
304     _Pragma(STDEXEC_STRINGIZE(GCC diagnostic ignored __VA_ARGS__))
305 #elif STDEXEC_MSVC()
306 #define STDEXEC_PRAGMA_PUSH() __pragma(warning(push))
307 #define STDEXEC_PRAGMA_POP() __pragma(warning(pop))
308 #define STDEXEC_PRAGMA_IGNORE_MSVC(...) __pragma(warning(disable : __VA_ARGS__))
309 #else
310 #define STDEXEC_PRAGMA_PUSH()
311 #define STDEXEC_PRAGMA_POP()
312 #endif
313 
314 #ifndef STDEXEC_PRAGMA_IGNORE_GNU
315 #define STDEXEC_PRAGMA_IGNORE_GNU(...)
316 #endif
317 #ifndef STDEXEC_PRAGMA_IGNORE_EDG
318 #define STDEXEC_PRAGMA_IGNORE_EDG(...)
319 #endif
320 #ifndef STDEXEC_PRAGMA_IGNORE_MSVC
321 #define STDEXEC_PRAGMA_IGNORE_MSVC(...)
322 #endif
323 
324 #if !STDEXEC_MSVC() && defined(__has_builtin)
325 #define STDEXEC_HAS_BUILTIN __has_builtin
326 #else
327 #define STDEXEC_HAS_BUILTIN(...) 0
328 #endif
329 
330 #if !STDEXEC_MSVC() && defined(__has_feature)
331 #define STDEXEC_HAS_FEATURE __has_feature
332 #else
333 #define STDEXEC_HAS_FEATURE(...) 0
334 #endif
335 
336 #if STDEXEC_HAS_BUILTIN(__is_trivially_copyable) || STDEXEC_MSVC()
337 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...) __is_trivially_copyable(__VA_ARGS__)
338 #else
339 #define STDEXEC_IS_TRIVIALLY_COPYABLE(...)                                     \
340     std::is_trivially_copyable_v<__VA_ARGS__>
341 #endif
342 
343 #if STDEXEC_HAS_BUILTIN(__is_base_of) || (_MSC_VER >= 1914)
344 #define STDEXEC_IS_BASE_OF(...) __is_base_of(__VA_ARGS__)
345 #else
346 #define STDEXEC_IS_BASE_OF(...) std::is_base_of_v<__VA_ARGS__>
347 #endif
348 
349 #if STDEXEC_HAS_BUILTIN(__is_convertible_to) || STDEXEC_MSVC()
350 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible_to(__VA_ARGS__)
351 #elif STDEXEC_HAS_BUILTIN(__is_convertible)
352 #define STDEXEC_IS_CONVERTIBLE_TO(...) __is_convertible(__VA_ARGS__)
353 #else
354 #define STDEXEC_IS_CONVERTIBLE_TO(...) std::is_convertible_v<__VA_ARGS__>
355 #endif
356 
357 #if STDEXEC_HAS_BUILTIN(__is_const)
358 #define STDEXEC_IS_CONST(...) __is_const(__VA_ARGS__)
359 #else
360 #define STDEXEC_IS_CONST(...) stdexec::__is_const_<__VA_ARGS__>
361 #endif
362 
363 #if STDEXEC_HAS_BUILTIN(__is_same)
364 #define STDEXEC_IS_SAME(...) __is_same(__VA_ARGS__)
365 #elif STDEXEC_HAS_BUILTIN(__is_same_as)
366 #define STDEXEC_IS_SAME(...) __is_same_as(__VA_ARGS__)
367 #elif STDEXEC_MSVC()
368 // msvc replaces std::is_same_v with a compile-time constant
369 #define STDEXEC_IS_SAME(...) std::is_same_v<__VA_ARGS__>
370 #else
371 #define STDEXEC_IS_SAME(...) stdexec::__same_as_v<__VA_ARGS__>
372 #endif
373 
374 #if STDEXEC_HAS_BUILTIN(__is_constructible) || STDEXEC_MSVC()
375 #define STDEXEC_IS_CONSTRUCTIBLE(...) __is_constructible(__VA_ARGS__)
376 #else
377 #define STDEXEC_IS_CONSTRUCTIBLE(...) std::is_constructible_v<__VA_ARGS__>
378 #endif
379 
380 #if STDEXEC_HAS_BUILTIN(__is_nothrow_constructible) || STDEXEC_MSVC()
381 #define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...)                                  \
382     __is_nothrow_constructible(__VA_ARGS__)
383 #else
384 #define STDEXEC_IS_NOTHROW_CONSTRUCTIBLE(...)                                  \
385     std::is_nothrow_constructible_v<__VA_ARGS__>
386 #endif
387 
388 #if STDEXEC_HAS_BUILTIN(__is_trivially_constructible) || STDEXEC_MSVC()
389 #define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...)                                \
390     __is_trivially_constructible(__VA_ARGS__)
391 #else
392 #define STDEXEC_IS_TRIVIALLY_CONSTRUCTIBLE(...)                                \
393     std::is_trivially_constructible_v<__VA_ARGS__>
394 #endif
395 
396 #if STDEXEC_HAS_BUILTIN(__is_empty) || STDEXEC_MSVC()
397 #define STDEXEC_IS_EMPTY(...) __is_empty(__VA_ARGS__)
398 #else
399 #define STDEXEC_IS_EMPTY(...) std::is_empty_v<__VA_ARGS__>
400 #endif
401 
402 #if STDEXEC_HAS_BUILTIN(__remove_reference)
403 namespace stdexec
404 {
405 template <class Ty>
406 using _remove_reference_t = __remove_reference(Ty);
407 } // namespace stdexec
408 
409 #define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__>
410 #elif STDEXEC_HAS_BUILTIN(__remove_reference_t)
411 namespace stdexec
412 {
413 template <class Ty>
414 using _remove_reference_t = __remove_reference_t(Ty);
415 } // namespace stdexec
416 
417 #define STDEXEC_REMOVE_REFERENCE(...) stdexec::_remove_reference_t<__VA_ARGS__>
418 #else
419 #define STDEXEC_REMOVE_REFERENCE(...) ::std::remove_reference_t<__VA_ARGS__>
420 #endif
421 
422 namespace stdexec
423 {
424 template <class _Ap, class _Bp>
425 inline constexpr bool __same_as_v = false;
426 
427 template <class _Ap>
428 inline constexpr bool __same_as_v<_Ap, _Ap> = true;
429 } // namespace stdexec
430 
431 #if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
432 #define STDEXEC_UNREACHABLE() std::unreachable()
433 #elif STDEXEC_HAS_BUILTIN(__builtin_unreachable)
434 #define STDEXEC_UNREACHABLE() __builtin_unreachable()
435 #elif STDEXEC_MSVC()
436 #define STDEXEC_UNREACHABLE(...) __assume(false)
437 #else
438 #define STDEXEC_UNREACHABLE(...) std::terminate()
439 #endif
440 
441 // Before gcc-12, gcc really didn't like tuples or variants of immovable types
442 #if STDEXEC_GCC() && (__GNUC__ < 12)
443 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&)
444 #else
445 #define STDEXEC_IMMOVABLE(_XP) _XP(_XP&&) = delete
446 #endif
447 
448 // BUG (gcc PR93711): copy elision fails when initializing a
449 // [[no_unique_address]] field from a function returning an object
450 // of class type by value
451 #if STDEXEC_GCC()
452 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
453 #else
454 #define STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS                                    \
455     STDEXEC_ATTRIBUTE((no_unique_address))
456 #endif
457 
458 #if STDEXEC_NVHPC()
459 #include <nv/target>
460 #define STDEXEC_TERMINATE()                                                    \
461     NV_IF_TARGET(NV_IS_HOST, (std::terminate();), (__trap();)) void()
462 #elif STDEXEC_CLANG() && STDEXEC_CUDA() && defined(__CUDA_ARCH__)
463 #define STDEXEC_TERMINATE()                                                    \
464     __trap();                                                                  \
465     __builtin_unreachable()
466 #else
467 #define STDEXEC_TERMINATE() std::terminate()
468 #endif
469 
470 #if STDEXEC_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__)
471 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
472 #else
473 #define STDEXEC_TSAN(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
474 #endif
475 
476 // Before clang-16, clang did not like libstdc++'s ranges implementation
477 #if __has_include(<ranges>) && \
478   (defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L) && \
479   (!STDEXEC_CLANG() || __clang_major__ >= 16 || defined(_LIBCPP_VERSION))
480 #define STDEXEC_HAS_STD_RANGES() 1
481 #else
482 #define STDEXEC_HAS_STD_RANGES() 0
483 #endif
484 
485 #if __has_include(<memory_resource>) && \
486   (defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L)
487 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 1
488 #else
489 #define STDEXEC_HAS_STD_MEMORY_RESOURCE() 0
490 #endif
491 
492 #ifdef STDEXEC_ASSERT
493 #error                                                                         \
494     "Redefinition of STDEXEC_ASSERT is not permitted. Define STDEXEC_ASSERT_FN instead."
495 #endif
496 
497 #define STDEXEC_ASSERT(_XP)                                                    \
498     do                                                                         \
499     {                                                                          \
500         static_assert(noexcept(_XP));                                          \
501         STDEXEC_ASSERT_FN(_XP);                                                \
502     } while (false)
503 
504 #ifndef STDEXEC_ASSERT_FN
505 #define STDEXEC_ASSERT_FN assert
506 #endif
507 
508 #define STDEXEC_AUTO_RETURN(...)                                               \
509     noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__)                     \
510     {                                                                          \
511         return __VA_ARGS__;                                                    \
512     }
513 
514 // GCC 13 implements lexical friendship, but it is incomplete. See
515 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111018
516 #if STDEXEC_CLANG() // || (STDEXEC_GCC() && __GNUC__ >= 13)
517 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 1
518 #else
519 #define STDEXEC_FRIENDSHIP_IS_LEXICAL() 0
520 #endif
521 
522 #if defined(__cpp_explicit_this_parameter) &&                                  \
523     (__cpp_explicit_this_parameter >= 202110)
524 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_TAIL(1, __VA_ARGS__)
525 #else
526 #define STDEXEC_EXPLICIT_THIS(...) STDEXEC_HEAD_OR_NULL(0, __VA_ARGS__)
527 #endif
528 
529 // Configure extra type checking
530 #define STDEXEC_TYPE_CHECKING_ZERO() 0
531 #define STDEXEC_TYPE_CHECKING_ONE() 1
532 #define STDEXEC_TYPE_CHECKING_TWO() 2
533 
534 #define STDEXEC_PROBE_TYPE_CHECKING_ STDEXEC_TYPE_CHECKING_ONE
535 #define STDEXEC_PROBE_TYPE_CHECKING_0 STDEXEC_TYPE_CHECKING_ZERO
536 #define STDEXEC_PROBE_TYPE_CHECKING_1 STDEXEC_TYPE_CHECKING_ONE
537 #define STDEXEC_PROBE_TYPE_CHECKING_STDEXEC_ENABLE_EXTRA_TYPE_CHECKING         \
538     STDEXEC_TYPE_CHECKING_TWO
539 
540 #define STDEXEC_TYPE_CHECKING_WHICH3(...)                                      \
541     STDEXEC_PROBE_TYPE_CHECKING_##__VA_ARGS__
542 #define STDEXEC_TYPE_CHECKING_WHICH2(...)                                      \
543     STDEXEC_TYPE_CHECKING_WHICH3(__VA_ARGS__)
544 #define STDEXEC_TYPE_CHECKING_WHICH                                            \
545     STDEXEC_TYPE_CHECKING_WHICH2(STDEXEC_ENABLE_EXTRA_TYPE_CHECKING)
546 
547 #ifndef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
548 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0
549 #elif STDEXEC_TYPE_CHECKING_WHICH() == 2
550 // do nothing
551 #elif STDEXEC_TYPE_CHECKING_WHICH() == 0
552 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
553 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 0
554 #else
555 #undef STDEXEC_ENABLE_EXTRA_TYPE_CHECKING
556 #define STDEXEC_ENABLE_EXTRA_TYPE_CHECKING() 1
557 #endif
558 
559 namespace stdexec
560 {}
561