| // 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/. |
| |
| #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. |
| // GCC > 5, 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_GNUC_STRICT_AT_LEAST(5, 0, 0) && (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 |