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 1 : #define ERROR(m) \ 67 : do { \ 68 : if (__builtin_is_constant_evaluated()) { \ 69 : throw std::runtime_error("Failed"); \ 70 : } else { \ 71 : Error_detail::abort_without_fpes<SpectreError>( \ 72 : __FILE__, __LINE__, static_cast<const char*>(__PRETTY_FUNCTION__), \ 73 : [&]() -> std::string { \ 74 : return MakeString{} << std::setprecision(18) << std::scientific \ 75 : << m; \ 76 : }); \ 77 : } \ 78 : } while (false) 79 : 80 : /*! 81 : * \ingroup ErrorHandlingGroup 82 : * \brief Same as ERROR but will throw `EXCEPTION_TYPE` instead of 83 : * `SpectreError`. 84 : * 85 : * \note Any exception types used must have an associated explicit 86 : * instantiation in `Utilities/ErrorHandling/AbortWithErrorMessage.cpp` 87 : */ 88 1 : #define ERROR_AS(m, EXCEPTION_TYPE) \ 89 : do { \ 90 : if (__builtin_is_constant_evaluated()) { \ 91 : throw std::runtime_error("Failed"); \ 92 : } else { \ 93 : Error_detail::abort_without_fpes<EXCEPTION_TYPE>( \ 94 : __FILE__, __LINE__, static_cast<const char*>(__PRETTY_FUNCTION__), \ 95 : [&]() -> std::string { \ 96 : return MakeString{} << std::setprecision(18) << std::scientific \ 97 : << m; \ 98 : }); \ 99 : } \ 100 : } while (false) 101 : 102 : /*! 103 : * \ingroup ErrorHandlingGroup 104 : * \brief Same as ERROR but does not print a backtrace. Intended to be used for 105 : * user errors, such as incorrect values in an input file. 106 : */ 107 1 : #define ERROR_NO_TRACE(m) \ 108 : do { \ 109 : if (__builtin_is_constant_evaluated()) { \ 110 : throw std::runtime_error("Failed"); \ 111 : } else { \ 112 : const ScopedFpeState disable_fpes_ERROR(false); \ 113 : abort_with_error_message_no_trace( \ 114 : __FILE__, __LINE__, static_cast<const char*>(__PRETTY_FUNCTION__), \ 115 : MakeString{} << std::setprecision(18) << std::scientific << m); \ 116 : } \ 117 : } while (false)