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
|