1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
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 
17 #pragma once
18 
19 #include <cstddef>
20 
21 #include <folly/CPortability.h>
22 #include <folly/portability/Config.h>
23 
24 #if defined(_MSC_VER)
25 #define FOLLY_CPLUSPLUS _MSVC_LANG
26 #else
27 #define FOLLY_CPLUSPLUS __cplusplus
28 #endif
29 
30 static_assert(FOLLY_CPLUSPLUS >= 201402L, "__cplusplus >= 201402L");
31 
32 #if defined(__GNUC__) && !defined(__clang__)
33 static_assert(__GNUC__ >= 5, "__GNUC__ >= 5");
34 #endif
35 
36 // Unaligned loads and stores
37 namespace folly {
38 #if FOLLY_HAVE_UNALIGNED_ACCESS
39 constexpr bool kHasUnalignedAccess = true;
40 #else
41 constexpr bool kHasUnalignedAccess = false;
42 #endif
43 } // namespace folly
44 
45 // compiler specific attribute translation
46 // msvc should come first, so if clang is in msvc mode it gets the right defines
47 
48 // NOTE: this will only do checking in msvc with versions that support /analyze
49 #ifdef _MSC_VER
50 #ifdef _USE_ATTRIBUTES_FOR_SAL
51 #undef _USE_ATTRIBUTES_FOR_SAL
52 #endif
53 /* nolint */
54 #define _USE_ATTRIBUTES_FOR_SAL 1
55 #include <sal.h> // @manual
56 #define FOLLY_PRINTF_FORMAT _Printf_format_string_
57 #define FOLLY_PRINTF_FORMAT_ATTR(format_param, dots_param) /**/
58 #else
59 #define FOLLY_PRINTF_FORMAT /**/
60 #define FOLLY_PRINTF_FORMAT_ATTR(format_param, dots_param) \
61   __attribute__((__format__(__printf__, format_param, dots_param)))
62 #endif
63 
64 // warn unused result
65 #if defined(__has_cpp_attribute)
66 #if __has_cpp_attribute(nodiscard)
67 #define FOLLY_NODISCARD [[nodiscard]]
68 #endif
69 #endif
70 #if !defined FOLLY_NODISCARD
71 #if defined(_MSC_VER) && (_MSC_VER >= 1700)
72 #define FOLLY_NODISCARD _Check_return_
73 #elif defined(__GNUC__)
74 #define FOLLY_NODISCARD __attribute__((__warn_unused_result__))
75 #else
76 #define FOLLY_NODISCARD
77 #endif
78 #endif
79 
80 // target
81 #ifdef _MSC_VER
82 #define FOLLY_TARGET_ATTRIBUTE(target)
83 #else
84 #define FOLLY_TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
85 #endif
86 
87 // detection for 64 bit
88 #if defined(__x86_64__) || defined(_M_X64)
89 #define FOLLY_X64 1
90 #else
91 #define FOLLY_X64 0
92 #endif
93 
94 #if defined(__arm__)
95 #define FOLLY_ARM 1
96 #else
97 #define FOLLY_ARM 0
98 #endif
99 
100 #if defined(__aarch64__)
101 #define FOLLY_AARCH64 1
102 #else
103 #define FOLLY_AARCH64 0
104 #endif
105 
106 #if defined(__powerpc64__)
107 #define FOLLY_PPC64 1
108 #else
109 #define FOLLY_PPC64 0
110 #endif
111 
112 #if defined(__s390x__)
113 #define FOLLY_S390X 1
114 #else
115 #define FOLLY_S390X 0
116 #endif
117 
118 namespace folly {
119 constexpr bool kIsArchArm = FOLLY_ARM == 1;
120 constexpr bool kIsArchAmd64 = FOLLY_X64 == 1;
121 constexpr bool kIsArchAArch64 = FOLLY_AARCH64 == 1;
122 constexpr bool kIsArchPPC64 = FOLLY_PPC64 == 1;
123 constexpr bool kIsArchS390X = FOLLY_S390X == 1;
124 } // namespace folly
125 
126 namespace folly {
127 
128 /**
129  * folly::kIsLibrarySanitizeAddress reports if folly was compiled with ASAN
130  * enabled.  Note that for compilation units outside of folly that include
131  * folly/Portability.h, the value of kIsLibrarySanitizeAddress may be different
132  * from whether or not the current compilation unit is being compiled with ASAN.
133  */
134 #if FOLLY_LIBRARY_SANITIZE_ADDRESS
135 constexpr bool kIsLibrarySanitizeAddress = true;
136 #else
137 constexpr bool kIsLibrarySanitizeAddress = false;
138 #endif
139 
140 #ifdef FOLLY_SANITIZE_ADDRESS
141 constexpr bool kIsSanitizeAddress = true;
142 #else
143 constexpr bool kIsSanitizeAddress = false;
144 #endif
145 
146 #ifdef FOLLY_SANITIZE_THREAD
147 constexpr bool kIsSanitizeThread = true;
148 #else
149 constexpr bool kIsSanitizeThread = false;
150 #endif
151 
152 #ifdef FOLLY_SANITIZE
153 constexpr bool kIsSanitize = true;
154 #else
155 constexpr bool kIsSanitize = false;
156 #endif
157 } // namespace folly
158 
159 // packing is very ugly in msvc
160 #ifdef _MSC_VER
161 #define FOLLY_PACK_ATTR /**/
162 #define FOLLY_PACK_PUSH __pragma(pack(push, 1))
163 #define FOLLY_PACK_POP __pragma(pack(pop))
164 #elif defined(__GNUC__)
165 #define FOLLY_PACK_ATTR __attribute__((__packed__))
166 #define FOLLY_PACK_PUSH /**/
167 #define FOLLY_PACK_POP /**/
168 #else
169 #define FOLLY_PACK_ATTR /**/
170 #define FOLLY_PACK_PUSH /**/
171 #define FOLLY_PACK_POP /**/
172 #endif
173 
174 // Generalize warning push/pop.
175 #if defined(__GNUC__) || defined(__clang__)
176 // Clang & GCC
177 #define FOLLY_PUSH_WARNING _Pragma("GCC diagnostic push")
178 #define FOLLY_POP_WARNING _Pragma("GCC diagnostic pop")
179 #define FOLLY_GNU_DISABLE_WARNING_INTERNAL2(warningName) #warningName
180 #define FOLLY_GNU_DISABLE_WARNING(warningName) \
181   _Pragma(                                     \
182       FOLLY_GNU_DISABLE_WARNING_INTERNAL2(GCC diagnostic ignored warningName))
183 #ifdef __clang__
184 #define FOLLY_CLANG_DISABLE_WARNING(warningName) \
185   FOLLY_GNU_DISABLE_WARNING(warningName)
186 #define FOLLY_GCC_DISABLE_WARNING(warningName)
187 #else
188 #define FOLLY_CLANG_DISABLE_WARNING(warningName)
189 #define FOLLY_GCC_DISABLE_WARNING(warningName) \
190   FOLLY_GNU_DISABLE_WARNING(warningName)
191 #endif
192 #define FOLLY_MSVC_DISABLE_WARNING(warningNumber)
193 #elif defined(_MSC_VER)
194 #define FOLLY_PUSH_WARNING __pragma(warning(push))
195 #define FOLLY_POP_WARNING __pragma(warning(pop))
196 // Disable the GCC warnings.
197 #define FOLLY_GNU_DISABLE_WARNING(warningName)
198 #define FOLLY_GCC_DISABLE_WARNING(warningName)
199 #define FOLLY_CLANG_DISABLE_WARNING(warningName)
200 #define FOLLY_MSVC_DISABLE_WARNING(warningNumber) \
201   __pragma(warning(disable : warningNumber))
202 #else
203 #define FOLLY_PUSH_WARNING
204 #define FOLLY_POP_WARNING
205 #define FOLLY_GNU_DISABLE_WARNING(warningName)
206 #define FOLLY_GCC_DISABLE_WARNING(warningName)
207 #define FOLLY_CLANG_DISABLE_WARNING(warningName)
208 #define FOLLY_MSVC_DISABLE_WARNING(warningNumber)
209 #endif
210 
211 #ifdef FOLLY_HAVE_SHADOW_LOCAL_WARNINGS
212 #define FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS            \
213   FOLLY_GNU_DISABLE_WARNING("-Wshadow-compatible-local") \
214   FOLLY_GNU_DISABLE_WARNING("-Wshadow-local")            \
215   FOLLY_GNU_DISABLE_WARNING("-Wshadow")
216 #else
217 #define FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS /* empty */
218 #endif
219 
220 // It turns out that GNU libstdc++ and LLVM libc++ differ on how they implement
221 // the 'std' namespace; the latter uses inline namespaces. Wrap this decision
222 // up in a macro to make forward-declarations easier.
223 #if defined(_LIBCPP_VERSION)
224 #define FOLLY_NAMESPACE_STD_BEGIN _LIBCPP_BEGIN_NAMESPACE_STD
225 #define FOLLY_NAMESPACE_STD_END _LIBCPP_END_NAMESPACE_STD
226 #else
227 #define FOLLY_NAMESPACE_STD_BEGIN namespace std {
228 #define FOLLY_NAMESPACE_STD_END }
229 #endif
230 
231 // If the new c++ ABI is used, __cxx11 inline namespace needs to be added to
232 // some types, e.g. std::list.
233 #if _GLIBCXX_USE_CXX11_ABI
234 #define FOLLY_GLIBCXX_NAMESPACE_CXX11_BEGIN \
235   inline _GLIBCXX_BEGIN_NAMESPACE_CXX11
236 #define FOLLY_GLIBCXX_NAMESPACE_CXX11_END _GLIBCXX_END_NAMESPACE_CXX11
237 #else
238 #define FOLLY_GLIBCXX_NAMESPACE_CXX11_BEGIN
239 #define FOLLY_GLIBCXX_NAMESPACE_CXX11_END
240 #endif
241 
242 // MSVC specific defines
243 // mainly for posix compat
244 #ifdef _MSC_VER
245 #include <folly/portability/SysTypes.h>
246 
247 // Hide a GCC specific thing that breaks MSVC if left alone.
248 #define __extension__
249 
250 // We have compiler support for the newest of the new, but
251 // MSVC doesn't tell us that.
252 //
253 // Clang pretends to be MSVC on Windows, but it refuses to compile
254 // SSE4.2 intrinsics unless -march argument is specified.
255 // So cannot unconditionally define __SSE4_2__ in clang.
256 #ifndef __clang__
257 #if !defined(_M_ARM) && !defined(_M_ARM64)
258 #define __SSE4_2__ 1
259 #endif // !defined(_M_ARM) && !defined(_M_ARM64)
260 
261 // compiler specific to compiler specific
262 // nolint
263 #define __PRETTY_FUNCTION__ __FUNCSIG__
264 #endif
265 
266 #endif
267 
268 // Define FOLLY_HAS_EXCEPTIONS
269 #if __cpp_exceptions >= 199711 || FOLLY_HAS_FEATURE(cxx_exceptions)
270 #define FOLLY_HAS_EXCEPTIONS 1
271 #elif __GNUC__
272 #if __EXCEPTIONS
273 #define FOLLY_HAS_EXCEPTIONS 1
274 #else // __EXCEPTIONS
275 #define FOLLY_HAS_EXCEPTIONS 0
276 #endif // __EXCEPTIONS
277 #elif FOLLY_MICROSOFT_ABI_VER
278 #if _CPPUNWIND
279 #define FOLLY_HAS_EXCEPTIONS 1
280 #else // _CPPUNWIND
281 #define FOLLY_HAS_EXCEPTIONS 0
282 #endif // _CPPUNWIND
283 #else
284 #define FOLLY_HAS_EXCEPTIONS 1 // default assumption for unknown platforms
285 #endif
286 
287 // Debug
288 namespace folly {
289 #ifdef NDEBUG
290 constexpr auto kIsDebug = false;
291 #else
292 constexpr auto kIsDebug = true;
293 #endif
294 } // namespace folly
295 
296 // Exceptions
297 namespace folly {
298 #if FOLLY_HAS_EXCEPTIONS
299 constexpr auto kHasExceptions = true;
300 #else
301 constexpr auto kHasExceptions = false;
302 #endif
303 } // namespace folly
304 
305 // Endianness
306 namespace folly {
307 #ifdef _MSC_VER
308 // It's MSVC, so we just have to guess ... and allow an override
309 #ifdef FOLLY_ENDIAN_BE
310 constexpr auto kIsLittleEndian = false;
311 #else
312 constexpr auto kIsLittleEndian = true;
313 #endif
314 #else
315 constexpr auto kIsLittleEndian = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
316 #endif
317 constexpr auto kIsBigEndian = !kIsLittleEndian;
318 } // namespace folly
319 
320 // Weak
321 namespace folly {
322 #if FOLLY_HAVE_WEAK_SYMBOLS
323 constexpr auto kHasWeakSymbols = true;
324 #else
325 constexpr auto kHasWeakSymbols = false;
326 #endif
327 } // namespace folly
328 
329 #ifndef FOLLY_SSE
330 #if defined(__SSE4_2__)
331 #define FOLLY_SSE 4
332 #define FOLLY_SSE_MINOR 2
333 #elif defined(__SSE4_1__)
334 #define FOLLY_SSE 4
335 #define FOLLY_SSE_MINOR 1
336 #elif defined(__SSE4__)
337 #define FOLLY_SSE 4
338 #define FOLLY_SSE_MINOR 0
339 #elif defined(__SSE3__)
340 #define FOLLY_SSE 3
341 #define FOLLY_SSE_MINOR 0
342 #elif defined(__SSE2__)
343 #define FOLLY_SSE 2
344 #define FOLLY_SSE_MINOR 0
345 #elif defined(__SSE__)
346 #define FOLLY_SSE 1
347 #define FOLLY_SSE_MINOR 0
348 #else
349 #define FOLLY_SSE 0
350 #define FOLLY_SSE_MINOR 0
351 #endif
352 #endif
353 
354 #ifndef FOLLY_SSSE
355 #if defined(__SSSE3__)
356 #define FOLLY_SSSE 3
357 #else
358 #define FOLLY_SSSE 0
359 #endif
360 #endif
361 
362 #define FOLLY_SSE_PREREQ(major, minor) \
363   (FOLLY_SSE > major || FOLLY_SSE == major && FOLLY_SSE_MINOR >= minor)
364 
365 #ifndef FOLLY_NEON
366 #if defined(__ARM_NEON) || defined(__ARM_NEON__)
367 #define FOLLY_NEON 1
368 #else
369 #define FOLLY_NEON 0
370 #endif
371 #endif
372 
373 #if FOLLY_UNUSUAL_GFLAGS_NAMESPACE
374 namespace FOLLY_GFLAGS_NAMESPACE {}
375 namespace gflags {
376 using namespace FOLLY_GFLAGS_NAMESPACE;
377 } // namespace gflags
378 #endif
379 
380 // RTTI may not be enabled for this compilation unit.
381 #if defined(__GXX_RTTI) || defined(__cpp_rtti) || \
382     (defined(_MSC_VER) && defined(_CPPRTTI))
383 #define FOLLY_HAS_RTTI 1
384 #else
385 #define FOLLY_HAS_RTTI 0
386 #endif
387 
388 namespace folly {
389 constexpr bool const kHasRtti = FOLLY_HAS_RTTI;
390 } // namespace folly
391 
392 #if defined(__APPLE__) || defined(_MSC_VER)
393 #define FOLLY_STATIC_CTOR_PRIORITY_MAX
394 #else
395 // 101 is the highest priority allowed by the init_priority attribute.
396 // This priority is already used by JEMalloc and other memory allocators so
397 // we will take the next one.
398 #define FOLLY_STATIC_CTOR_PRIORITY_MAX __attribute__((__init_priority__(102)))
399 #endif
400 
401 #if defined(__APPLE__) && TARGET_OS_IOS
402 #define FOLLY_APPLE_IOS 1
403 #else
404 #define FOLLY_APPLE_IOS 0
405 #endif
406 
407 #if defined(__APPLE__) && TARGET_OS_OSX
408 #define FOLLY_APPLE_MACOS 1
409 #else
410 #define FOLLY_APPLE_MACOS 0
411 #endif
412 
413 #if defined(__APPLE__) && TARGET_OS_TV
414 #define FOLLY_APPLE_TVOS 1
415 #else
416 #define FOLLY_APPLE_TVOS 0
417 #endif
418 
419 #if defined(__APPLE__) && TARGET_OS_WATCH
420 #define FOLLY_APPLE_WATCHOS 1
421 #else
422 #define FOLLY_APPLE_WATCHOS 0
423 #endif
424 
425 namespace folly {
426 
427 #ifdef __OBJC__
428 constexpr auto kIsObjC = true;
429 #else
430 constexpr auto kIsObjC = false;
431 #endif
432 
433 #if FOLLY_MOBILE
434 constexpr auto kIsMobile = true;
435 #else
436 constexpr auto kIsMobile = false;
437 #endif
438 
439 #if defined(__linux__) && !FOLLY_MOBILE
440 constexpr auto kIsLinux = true;
441 #else
442 constexpr auto kIsLinux = false;
443 #endif
444 
445 #if defined(_WIN32)
446 constexpr auto kIsWindows = true;
447 #else
448 constexpr auto kIsWindows = false;
449 #endif
450 
451 #if defined(__APPLE__)
452 constexpr auto kIsApple = true;
453 #else
454 constexpr auto kIsApple = false;
455 #endif
456 
457 constexpr bool kIsAppleIOS = FOLLY_APPLE_IOS == 1;
458 constexpr bool kIsAppleMacOS = FOLLY_APPLE_MACOS == 1;
459 constexpr bool kIsAppleTVOS = FOLLY_APPLE_TVOS == 1;
460 constexpr bool kIsAppleWatchOS = FOLLY_APPLE_WATCHOS == 1;
461 
462 #if __GLIBCXX__
463 constexpr auto kIsGlibcxx = true;
464 #else
465 constexpr auto kIsGlibcxx = false;
466 #endif
467 
468 #if __GLIBCXX__ && _GLIBCXX_RELEASE // major version, 7+
469 constexpr auto kGlibcxxVer = _GLIBCXX_RELEASE;
470 #else
471 constexpr auto kGlibcxxVer = 0;
472 #endif
473 
474 #if __GLIBCXX__ && defined(_GLIBCXX_ASSERTIONS)
475 constexpr auto kGlibcxxAssertions = true;
476 #else
477 constexpr auto kGlibcxxAssertions = false;
478 #endif
479 
480 #ifdef _LIBCPP_VERSION
481 constexpr auto kIsLibcpp = true;
482 #else
483 constexpr auto kIsLibcpp = false;
484 #endif
485 
486 #if __GLIBCXX__
487 constexpr auto kIsLibstdcpp = true;
488 #else
489 constexpr auto kIsLibstdcpp = false;
490 #endif
491 
492 #ifdef _MSC_VER
493 constexpr auto kMscVer = _MSC_VER;
494 #else
495 constexpr auto kMscVer = 0;
496 #endif
497 
498 #if __GNUC__
499 constexpr auto kGnuc = __GNUC__;
500 #else
501 constexpr auto kGnuc = 0;
502 #endif
503 
504 #if __clang__
505 constexpr auto kIsClang = true;
506 constexpr auto kClangVerMajor = __clang_major__;
507 #else
508 constexpr auto kIsClang = false;
509 constexpr auto kClangVerMajor = 0;
510 #endif
511 
512 #ifdef FOLLY_MICROSOFT_ABI_VER
513 constexpr auto kMicrosoftAbiVer = FOLLY_MICROSOFT_ABI_VER;
514 #else
515 constexpr auto kMicrosoftAbiVer = 0;
516 #endif
517 
518 // cpplib is an implementation of the standard library, and is the one typically
519 // used with the msvc compiler
520 #ifdef _CPPLIB_VER
521 constexpr auto kCpplibVer = _CPPLIB_VER;
522 #else
523 constexpr auto kCpplibVer = 0;
524 #endif
525 } // namespace folly
526 
527 //  MSVC does not permit:
528 //
529 //    extern int const num;
530 //    constexpr int const num = 3;
531 //
532 //  Instead:
533 //
534 //    extern int const num;
535 //    FOLLY_STORAGE_CONSTEXPR int const num = 3;
536 //
537 //  True as of MSVC 2017.
538 #ifdef _MSC_VER
539 #define FOLLY_STORAGE_CONSTEXPR
540 #else
541 #define FOLLY_STORAGE_CONSTEXPR constexpr
542 #endif
543 
544 //  FOLLY_CXX17_CONSTEXPR
545 //
546 //  C++17 permits more cases to be marked constexpr, including lambda bodies and
547 //  the `if` keyword.
548 #if FOLLY_CPLUSPLUS >= 201703L
549 #define FOLLY_CXX17_CONSTEXPR constexpr
550 #else
551 #define FOLLY_CXX17_CONSTEXPR
552 #endif
553 
554 #if __cplusplus >= 201703L
555 // folly::coro requires C++17 support
556 #if defined(_WIN32) && defined(__clang__) && !defined(LLVM_COROUTINES)
557 // LLVM and MSVC coroutines are ABI incompatible, so for the MSVC implementation
558 // of <experimental/coroutine> on Windows we *don't* have coroutines.
559 //
560 // LLVM_COROUTINES indicates that LLVM compatible header is added to include
561 // path and can be used.
562 //
563 // Worse, if we define FOLLY_HAS_COROUTINES 1 we will include
564 // <experimental/coroutine> which will conflict with anyone who wants to load
565 // the LLVM implementation of coroutines on Windows.
566 #define FOLLY_HAS_COROUTINES 0
567 #elif (__cpp_coroutines >= 201703L || __cpp_impl_coroutine >= 201902L) && \
568     (__has_include(<coroutine>) || __has_include(<experimental/coroutine>))
569 #define FOLLY_HAS_COROUTINES 1
570 // This is mainly to workaround bugs triggered by LTO, when stack allocated
571 // variables in await_suspend end up on a coroutine frame.
572 #define FOLLY_CORO_AWAIT_SUSPEND_NONTRIVIAL_ATTRIBUTES FOLLY_NOINLINE
573 #elif _MSC_VER && _RESUMABLE_FUNCTIONS_SUPPORTED
574 // NOTE: MSVC 2017 does not currently support the full Coroutines TS since it
575 // does not yet support symmetric-transfer.
576 #define FOLLY_HAS_COROUTINES 0
577 #else
578 #define FOLLY_HAS_COROUTINES 0
579 #endif
580 #else
581 #define FOLLY_HAS_COROUTINES 0
582 #endif // __cplusplus >= 201703L
583 
584 // MSVC 2017.5 && C++17
585 #if __cpp_noexcept_function_type >= 201510 || \
586     (_MSC_FULL_VER >= 191225816 && _MSVC_LANG > 201402)
587 #define FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE 1
588 #endif
589 
590 #if __cpp_inline_variables >= 201606L
591 #define FOLLY_HAS_INLINE_VARIABLES 1
592 #define FOLLY_INLINE_VARIABLE inline
593 #else
594 #define FOLLY_HAS_INLINE_VARIABLES 0
595 #define FOLLY_INLINE_VARIABLE
596 #endif
597 
598 // feature test __cpp_lib_string_view is defined in <string>, which is
599 // too heavy to include here.
600 #if __has_include(<string_view>) && FOLLY_CPLUSPLUS >= 201703L
601 #define FOLLY_HAS_STRING_VIEW 1
602 #else
603 #define FOLLY_HAS_STRING_VIEW 0
604 #endif
605