| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2022, The Eigen authors. | |
| // | |
| // This Source Code Form is subject to the terms of the Mozilla | |
| // Public License v. 2.0. If a copy of the MPL was not distributed | |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_CORE_UTIL_ASSERT_H | |
| #define EIGEN_CORE_UTIL_ASSERT_H | |
| // Eigen custom assert function. | |
| // | |
| // The combination of Eigen's relative includes and cassert's `assert` function | |
| // (or any usage of the __FILE__ macro) can lead to ODR issues: | |
| // a header included using different relative paths in two different TUs will | |
| // have two different token-for-token definitions, since __FILE__ is expanded | |
| // as an in-line string with different values. Normally this would be | |
| // harmless - the linker would just choose one definition. However, it breaks | |
| // with C++20 modules when functions in different modules have different | |
| // definitions. | |
| // | |
| // To get around this, we need to use __builtin_FILE() when available, which is | |
| // considered a single token, and thus satisfies the ODR. | |
| // Only define eigen_plain_assert if we are debugging, and either | |
| // - we are not compiling for GPU, or | |
| // - gpu debugging is enabled. | |
| #if !defined(EIGEN_NO_DEBUG) && (!defined(EIGEN_GPU_COMPILE_PHASE) || !defined(EIGEN_NO_DEBUG_GPU)) | |
| #include <cassert> | |
| #ifndef EIGEN_USE_CUSTOM_PLAIN_ASSERT | |
| // Disable new custom asserts by default for now. | |
| #define EIGEN_USE_CUSTOM_PLAIN_ASSERT 0 | |
| #endif | |
| #if EIGEN_USE_CUSTOM_PLAIN_ASSERT | |
| #ifndef EIGEN_HAS_BUILTIN_FILE | |
| // Clang can check if __builtin_FILE() is supported. | |
| // Supported GCC versions and MSVC 2019 14.26 (1926) all have __builtin_FILE(). | |
| // | |
| // For NVCC, it's more complicated. Through trial-and-error: | |
| // - nvcc+gcc supports __builtin_FILE() on host, and on device after CUDA 11. | |
| // - nvcc+msvc supports __builtin_FILE() only after CUDA 11. | |
| #if (EIGEN_HAS_BUILTIN(__builtin_FILE) && (EIGEN_COMP_CLANG || !defined(EIGEN_CUDA_ARCH))) || \ | |
| (EIGEN_COMP_GNUC_STRICT && (EIGEN_COMP_NVCC >= 110000 || !defined(EIGEN_CUDA_ARCH))) || \ | |
| (EIGEN_COMP_MSVC >= 1926 && (!EIGEN_COMP_NVCC || EIGEN_COMP_NVCC >= 110000)) | |
| #define EIGEN_HAS_BUILTIN_FILE 1 | |
| #else | |
| #define EIGEN_HAS_BUILTIN_FILE 0 | |
| #endif | |
| #endif // EIGEN_HAS_BUILTIN_FILE | |
| #if EIGEN_HAS_BUILTIN_FILE | |
| #define EIGEN_BUILTIN_FILE __builtin_FILE() | |
| #define EIGEN_BUILTIN_LINE __builtin_LINE() | |
| #else | |
| // Default (potentially unsafe) values. | |
| #define EIGEN_BUILTIN_FILE __FILE__ | |
| #define EIGEN_BUILTIN_LINE __LINE__ | |
| #endif | |
| // Use __PRETTY_FUNCTION__ when available, since it is more descriptive, as | |
| // __builtin_FUNCTION() only returns the undecorated function name. | |
| // This should still be okay ODR-wise since it is a compiler-specific fixed | |
| // value. Mixing compilers will likely lead to ODR violations anyways. | |
| #if EIGEN_COMP_MSVC | |
| #define EIGEN_BUILTIN_FUNCTION __FUNCSIG__ | |
| #elif EIGEN_COMP_GNUC | |
| #define EIGEN_BUILTIN_FUNCTION __PRETTY_FUNCTION__ | |
| #else | |
| #define EIGEN_BUILTIN_FUNCTION __func__ | |
| #endif | |
| namespace Eigen { | |
| namespace internal { | |
| // Generic default assert handler. | |
| template <typename EnableIf = void, typename... EmptyArgs> | |
| struct assert_handler_impl { | |
| EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE static inline void run(const char* expression, const char* file, unsigned line, | |
| const char* function) { | |
| #ifdef EIGEN_GPU_COMPILE_PHASE | |
| // GPU device code doesn't allow stderr or abort, so use printf and raise an | |
| // illegal instruction exception to trigger a kernel failure. | |
| #ifndef EIGEN_NO_IO | |
| printf("Assertion failed at %s:%u in %s: %s\n", file == nullptr ? "<file>" : file, line, | |
| function == nullptr ? "<function>" : function, expression); | |
| #endif | |
| __trap(); | |
| #else // EIGEN_GPU_COMPILE_PHASE | |
| // Print to stderr and abort, as specified in <cassert>. | |
| #ifndef EIGEN_NO_IO | |
| fprintf(stderr, "Assertion failed at %s:%u in %s: %s\n", file == nullptr ? "<file>" : file, line, | |
| function == nullptr ? "<function>" : function, expression); | |
| #endif | |
| std::abort(); | |
| #endif // EIGEN_GPU_COMPILE_PHASE | |
| } | |
| }; | |
| // Use POSIX __assert_fail handler when available. | |
| // | |
| // This allows us to integrate with systems that have custom handlers. | |
| // | |
| // NOTE: this handler is not always available on all POSIX systems (otherwise | |
| // we could simply test for __unix__ or similar). The handler function name | |
| // seems to depend on the specific toolchain implementation, and differs between | |
| // compilers, platforms, OSes, etc. Hence, we detect support via SFINAE. | |
| template <typename... EmptyArgs> | |
| struct assert_handler_impl<void_t<decltype(__assert_fail((const char*)nullptr, // expression | |
| (const char*)nullptr, // file | |
| 0, // line | |
| (const char*)nullptr, // function | |
| std::declval<EmptyArgs>()... // Empty substitution required | |
| // for SFINAE. | |
| ))>, | |
| EmptyArgs...> { | |
| EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE static inline void run(const char* expression, const char* file, unsigned line, | |
| const char* function) { | |
| // GCC requires this call to be dependent on the template parameters. | |
| __assert_fail(expression, file, line, function, std::declval<EmptyArgs>()...); | |
| } | |
| }; | |
| EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE inline void __assert_handler(const char* expression, const char* file, | |
| unsigned line, const char* function) { | |
| assert_handler_impl<>::run(expression, file, line, function); | |
| } | |
| } // namespace internal | |
| } // namespace Eigen | |
| #define eigen_plain_assert(expression) \ | |
| (EIGEN_PREDICT_FALSE(!(expression)) ? Eigen::internal::__assert_handler(#expression, EIGEN_BUILTIN_FILE, \ | |
| EIGEN_BUILTIN_LINE, EIGEN_BUILTIN_FUNCTION) \ | |
| : (void)0) | |
| #else // EIGEN_USE_CUSTOM_PLAIN_ASSERT | |
| // Use regular assert. | |
| #define eigen_plain_assert(condition) assert(condition) | |
| #endif // EIGEN_USE_CUSTOM_PLAIN_ASSERT | |
| #else // EIGEN_NO_DEBUG | |
| #define eigen_plain_assert(condition) ((void)0) | |
| #endif // EIGEN_NO_DEBUG | |
| #endif // EIGEN_CORE_UTIL_ASSERT_H |