Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Defines macro ERROR. 6 : 7 : #pragma once 8 : 9 : #include <iomanip> 10 : #include <string> 11 : 12 : #include "Utilities/ErrorHandling/AbortWithErrorMessage.hpp" 13 : #include "Utilities/ErrorHandling/Breakpoint.hpp" 14 : #include "Utilities/ErrorHandling/Exceptions.hpp" 15 : #include "Utilities/ErrorHandling/FloatingPointExceptions.hpp" 16 : #include "Utilities/ForceInline.hpp" 17 : #include "Utilities/Literals.hpp" 18 : #include "Utilities/MakeString.hpp" 19 : #include "Utilities/System/Abort.hpp" 20 : 21 : namespace Error_detail { 22 : // You can't use ScopedFpeState (a non-literal type) in a constexpr 23 : // function, but you can call another function that uses it. 24 : template <typename ExceptionTypeToThrow, typename F> 25 : [[noreturn]] SPECTRE_ALWAYS_INLINE void abort_without_fpes( 26 : const char* file, const int line, const char* const pretty_function, 27 : F&& message) { 28 : const ScopedFpeState disable_fpes(false); 29 : abort_with_error_message<ExceptionTypeToThrow>(file, line, pretty_function, 30 : message()); 31 : } 32 : } // namespace Error_detail 33 : 34 : /*! 35 : * \ingroup ErrorHandlingGroup 36 : * \brief prints an error message to the standard error stream and aborts the 37 : * program. 38 : * 39 : * ERROR should not be used for coding errors, but instead for user errors 40 : * or failure modes of numerical algorithms. An acceptable use for error is also 41 : * in the default case of a switch statement. 42 : * 43 : * \details 44 : * The implementation is specialized so that in compile time contexts, a short 45 : * error message will be thrown, but in runtime contexts, a more verbose error 46 : * will be printed. This specialization of throwing a short error at compile 47 : * time greatly reduces the compile time and memory consumption during debug 48 : * builds of deep and heavily inlined `TensorExpression` tree traversals. 49 : * 50 : * To accomplish this, `__builtin_is_constant_evaluated()` is used directly 51 : * instead of calling a wrapper function because calling a wrapper was found to 52 : * slightly increase the compile time and memory usage of large 53 : * `TensorExpression`s when compiling in debug mode. 54 : * 55 : * \param m an arbitrary output stream. 56 : */ 57 : // isocpp.org recommends using an `if (true)` instead of a `do 58 : // while(false)` for macros because the latter can mess with inlining 59 : // in some (old?) compilers: 60 : // https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-multi-stmts 61 : // https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-if 62 : // However, Intel's reachability analyzer (as of version 16.0.3 63 : // 20160415) can't figure out that the else branch and everything 64 : // after it is unreachable, causing warnings (and possibly suboptimal 65 : // code generation). 66 : #ifdef __CUDA_ARCH__ 67 : #if defined(__clang__) && defined(__CUDA__) 68 : #define ERROR(m) \ 69 : printf("Error in file %s on line %d.", __FILE__, __LINE__); \ 70 : __builtin_trap(); 71 : #else 72 : #define ERROR(m) \ 73 : printf("Error in file %s on line %d.", __FILE__, __LINE__); \ 74 : __trap(); 75 : #endif 76 : #else 77 1 : #define ERROR(m) \ 78 : do { \ 79 : if (__builtin_is_constant_evaluated()) { \ 80 : throw std::runtime_error("Failed"); \ 81 : } else { \ 82 : Error_detail::abort_without_fpes<SpectreError>( \ 83 : __FILE__, __LINE__, static_cast<const char*>(__PRETTY_FUNCTION__), \ 84 : [&]() -> std::string { \ 85 : return MakeString{} << std::setprecision(18) << std::scientific \ 86 : << m; \ 87 : }); \ 88 : } \ 89 : } while (false) 90 : #endif 91 : 92 : /*! 93 : * \ingroup ErrorHandlingGroup 94 : * \brief Same as ERROR but will throw `EXCEPTION_TYPE` instead of 95 : * `SpectreError`. 96 : * 97 : * \note Any exception types used must have an associated explicit 98 : * instantiation in `Utilities/ErrorHandling/AbortWithErrorMessage.cpp` 99 : */ 100 : #ifdef __CUDA_ARCH__ 101 : #if defined(__clang__) && defined(__CUDA__) 102 : #define ERROR_AS(m, EXCEPTION_TYPE) \ 103 : printf("Error in file %s on line %d.", __FILE__, __LINE__); \ 104 : __builtin_trap(); 105 : #else 106 : #define ERROR_AS(m, EXCEPTION_TYPE) \ 107 : printf("Error in file %s on line %d.", __FILE__, __LINE__); \ 108 : __trap(); 109 : #endif 110 : #else 111 1 : #define ERROR_AS(m, EXCEPTION_TYPE) \ 112 : do { \ 113 : if (__builtin_is_constant_evaluated()) { \ 114 : throw std::runtime_error("Failed"); \ 115 : } else { \ 116 : Error_detail::abort_without_fpes<EXCEPTION_TYPE>( \ 117 : __FILE__, __LINE__, static_cast<const char*>(__PRETTY_FUNCTION__), \ 118 : [&]() -> std::string { \ 119 : return MakeString{} << std::setprecision(18) << std::scientific \ 120 : << m; \ 121 : }); \ 122 : } \ 123 : } while (false) 124 : #endif 125 : 126 : /*! 127 : * \ingroup ErrorHandlingGroup 128 : * \brief Same as ERROR but does not print a backtrace. Intended to be used for 129 : * user errors, such as incorrect values in an input file. 130 : */ 131 : #ifdef __CUDA_ARCH__ 132 : #if defined(__clang__) && defined(__CUDA__) 133 : #define ERROR_NO_TRACE(m) \ 134 : printf("Error in file %s on line %d.", __FILE__, __LINE__); \ 135 : __builtin_trap(); 136 : #else 137 : #define ERROR_NO_TRACE(m) \ 138 : printf("Error in file %s on line %d.", __FILE__, __LINE__); \ 139 : __trap(); 140 : #endif 141 : #else 142 1 : #define ERROR_NO_TRACE(m) \ 143 : do { \ 144 : if (__builtin_is_constant_evaluated()) { \ 145 : throw std::runtime_error("Failed"); \ 146 : } else { \ 147 : const ScopedFpeState disable_fpes_ERROR(false); \ 148 : abort_with_error_message_no_trace( \ 149 : __FILE__, __LINE__, static_cast<const char*>(__PRETTY_FUNCTION__), \ 150 : MakeString{} << std::setprecision(18) << std::scientific << m); \ 151 : } \ 152 : } while (false) 153 : #endif